diff --git a/rfcs/0016-claws.md b/rfcs/0016-claws.md new file mode 100644 index 00000000..e19633e2 --- /dev/null +++ b/rfcs/0016-claws.md @@ -0,0 +1,963 @@ +--- +title: Claws +authors: + - Gio +created: 2026-07-03 +last_updated: 2026-07-19 +status: draft +issue: +rfc_pr: https://github.com/openclaw/rfcs/pull/27 +--- + +# Proposal: Claws + +## Summary + +Define a **Claw** as a distributable definition of one complete OpenClaw agent +for one job. Adding a Claw creates a new local agent, creates that agent's +workspace, installs its skills and plugin dependencies, configures declared MCP +servers, creates agent-pinned scheduled work, and records provenance for the +complete installed agent. + +The central invariant is: + +> One Claw package adds one new agent for one job. It does not merge into, +> replace, or silently update an agent the operator already built. + +Claws compose existing OpenClaw primitives. Skills remain skills, plugins remain +plugins, MCP servers remain top-level OpenClaw MCP configuration, heartbeat +remains agent configuration, and cron jobs remain Gateway scheduler records. +The Claw owns their composition and lifecycle for the new agent; it does not +replace the underlying owner surfaces. + +The public lifecycle is `add`, `status`, `update`, `remove`, and `export`. +`add --dry-run` is the non-mutating preview. Artifact-level `install` and +`uninstall` remain the underlying operations for individual skills and plugins. + +## Motivation + +A useful Claw should feel like adding a purpose-built employee to OpenClaw. For +example, adding `@acme/github-triage` creates a GitHub triage agent with its own +workspace, instructions, skills, tools, MCP dependency, heartbeat behavior, and +scheduled triage job. It does not rewrite the default agent or borrow an +unrelated workspace. + +Adding a Claw always plans the following owned resources: + +1. One new `agents.list[]` entry. +2. One new workspace assigned to that agent. +3. Canonical bootstrap files and supporting files in that workspace. +4. Workspace skills and global plugin dependencies. +5. Declared MCP servers in OpenClaw's top-level `mcp.servers` configuration. +6. Declared cron jobs stored in the Gateway scheduler and pinned to the new + agent id. +7. Provenance connecting every created or referenced resource to the installed + Claw and local agent. + +The manifest's `agent.id` supplies the default local agent id. If that id or its +default workspace already exists, `add` fails closed. A user may explicitly +choose a different id with `--agent-id`; OpenClaw derives a matching unused +workspace unless `--workspace` is also supplied. Neither override permits +adopting or merging into an existing agent or managed workspace. + +## Goals + +- Make a complete job-specific agent distributable as plain, reviewable data. +- Preserve the one-Claw-one-new-agent invariant across CLI, schema, provenance, + updates, removal, export, feeds, and future UI. +- Keep individual skill and plugin packages on their existing install and + safety paths. +- Create agent workspaces without modifying existing agents or operator + defaults. +- Distinguish canonical workspace bootstrap files from ordinary supporting + files. +- Allow portable, job-specific agent settings while excluding operator-owned + runtime and authentication choices. +- Preview every config, file, package, MCP, and cron mutation before `add`. +- Fail the complete add when any declared component cannot be applied. +- Record enough provenance to inspect, diagnose, update, export, and remove the + installed agent safely. +- Reuse RFC 0009 feeds for discovery, curation, approval, blocking, and exact + source resolution of plugin and skill packages without turning MCP server + declarations into catalog entries. +- Keep Claw processing out of the per-turn Gateway hot path. + +## Non-goals + +- Modifying, templating over, or adopting an existing agent. +- Importing a complete running OpenClaw instance, sessions, logs, caches, + memories, channel bindings, OAuth state, or credentials. +- Replacing standalone skill, plugin, MCP, cron, heartbeat, or agent config + surfaces. +- Replacing plugin-bundled companion skills. +- Defining a new package registry, credential store, or dependency solver. +- Embedding model, provider, thinking-level, authentication, or other + operator-controlled runtime defaults. +- Embedding channel account ids, group ids, credentials, or bindings. +- Setting `agents.list[].skills`; workspace-installed skills remain naturally + discoverable and must not replace inherited allowlists. +- Defining a generic `connector` installation concept. Channel capabilities are + supplied by normal channel plugins and configured or bound locally. +- Defining a feed-backed MCP connector catalog or replacing the Control UI's + separately curated connector suggestions. +- Silently enabling recurring work without preview, consent, provenance, and a + disable/remove path. + +## Proposal + +### Normative principles + +Accepting this RFC accepts the following stable product contract. Individual +implementation slices may land separately, but later work must preserve these +principles. + +| Principle | Requirement | +| --- | --- | +| Unit of ownership | One Claw describes exactly one new agent and its owned setup. | +| Existing agents | `add` never merges into or updates an existing agent. Agent-id and workspace collisions fail closed. | +| Lifecycle verb | The creation operation is `claws add`; `install` remains an artifact-level operation. | +| Public schema | The manifest uses grouped `agent`, `workspace`, `packages`, `mcpServers`, and `cronJobs` fields rather than a generic flat entry list. | +| Completeness | Every declared component is part of the Claw. Unsupported, blocked, or invalid components block `add`; there is no optional `required` flag. | +| Package identity | Package name and version come from the enclosing package metadata and authenticated publish operation, following the ClawHub plugin precedent. | +| Operator control | Models, providers, credentials, channel bindings, and local runtime defaults are not portable Claw settings. | +| Agent configuration | Only explicitly supported portable job settings can be copied into the new `agents.list[]` entry. | +| Skills | Skill packages install into the new agent's workspace and are discovered normally; the Claw does not set `agent.skills`. | +| Plugins | Plugin packages use existing plugin installers, safety checks, enablement rules, and install records. | +| Discovery and composition | Hosted feeds discover and govern plugin and skill packages; a Claw composes exact resolved package versions and direct MCP declarations rather than defining another catalog. | +| MCP | Portable stdio and remote MCP declarations map to top-level `mcp.servers`; credentials and completed OAuth state remain local and are not persisted in the manifest or Claw provenance. | +| Scheduled work | Heartbeat is agent behavior; exact schedules are Gateway cron jobs pinned to the new agent id. | +| Mutation | `add --dry-run` is read-only. Mutating add requires explicit consent. | +| Provenance | OpenClaw records the installed Claw, local agent id, workspace, package refs, MCP refs, cron refs, and managed-file hashes in shared state. | +| Removal | `remove` deletes only Claw-owned state after drift checks and preserves local edits and independently owned artifacts. | + +### Managed and referenced resources + +Claws use one ownership model across every capability. A resource relationship +is either **managed** or **referenced**: + +- A **managed resource** is created specifically for the installed Claw and has + an exclusive Claw identity. The Claw lifecycle may reconcile and remove it + after revalidating ownership and drift. The created agent, its workspace + files, agent-pinned cron jobs, and a newly created collision-free MCP + declaration are managed resources. +- A **referenced resource** is a shared resource on which the Claw depends. The + lifecycle records a current dependency edge but does not acquire exclusive + authority over the resource. Shared package artifacts and plugins are + referenced even when Claw add introduced them through their canonical + installer. An identical pre-existing MCP declaration may also be referenced. + +The canonical owner identity, not the capability label alone, determines the +relationship. For example, a skill directory materialized exclusively inside +the new agent workspace is managed workspace state, while a skill installation +shared outside that workspace is referenced. + +Resource origin (`claw-introduced` or `pre-existing`) is cleanup evidence, not +a third ownership mode. Provenance stores current resource identities, +integrity, dependency edges, and incomplete cleanup state. It does not maintain +historical reference counts or an operation-history ledger. + +Every owner follows the same lifecycle rules: dry-run reports the relationship +and expected state; add either creates a managed resource or satisfies a +reference through the canonical owner; update revalidates before reconciling; +status distinguishes recorded state from live state; and remove deletes managed +resources while retaining referenced resources by default. + +### Package and manifest identity + +The implementer-facing package contract is captured in +[`0016/claw-package-v1-spec.md`](0016/claw-package-v1-spec.md). The experimental +human-readable envelope is captured separately in +[`0016/claw-md-v1-spec.md`](0016/claw-md-v1-spec.md). This RFC remains the +product rationale, ownership model, lifecycle, and rollout plan. + +A published Claw follows the current ClawHub plugin precedent. Registry identity, +version, and publisher ownership come from the enclosing package and the +authenticated publish operation, not duplicated manifest fields. + +Illustrative `package.json`: + +```json +{ + "name": "@acme/github-triage", + "version": "1.2.0", + "type": "module", + "openclaw": { + "claw": "openclaw.claw.json" + } +} +``` + +The Claw manifest therefore does not repeat a top-level publisher, package slug, +package version, display name, or description. A local unpackaged manifest may +be inspected during development, but mutating local add must synthesize an +explicit development identity and record its canonical source path and digest. + +The experimental implementation accepts the strict grouped JSON representation +and `CLAW.md`, in which YAML frontmatter carries the same typed manifest and the +Markdown body is documentation only. Export emits `CLAW.md`; JSON remains a +fully supported serialization of the same grouped schema. + +Both representations are covered by the existing +`OPENCLAW_EXPERIMENTAL_CLAWS=1` gate. `CLAW.md` adds only reader/export format +adaptation and no schema, lifecycle, provenance, or ownership branch. While the +RFC remains experimental, maintainers may revise or remove that envelope before +graduation without creating a separate compatibility promise. + +Feeds and registries materialize an exact package version and integrity before +add. Mutable tags and floating ranges must not become managed installs without +that resolution step. + +### Manifest schema + +The initial public shape is grouped by OpenClaw ownership boundary: + +```jsonc +{ + "schemaVersion": 1, + "agent": { + "id": "github-triage", + "name": "GitHub Triage", + "description": "Reviews incoming GitHub issues and prepares a daily triage summary.", + "identity": { + "name": "Triage", + "emoji": "🔎" + }, + "groupChat": { + "mentionPatterns": ["@triage", "@github-triage"] + }, + "sandbox": { + "mode": "all", + "scope": "agent", + "workspaceAccess": "rw" + }, + "tools": { + "allow": ["read", "write", "edit", "web_fetch", "memory_search", "memory_get"], + "deny": ["exec", "browser", "nodes"] + }, + "heartbeat": { + "every": "30m", + "activeHours": { + "start": "08:00", + "end": "18:00" + }, + "lightContext": true, + "isolatedSession": true, + "skipWhenBusy": true, + "timeoutSeconds": 120 + }, + "humanDelay": { + "mode": "natural" + } + }, + "workspace": { + "bootstrapFiles": { + "AGENTS.md": { "source": "workspace/AGENTS.md" }, + "SOUL.md": { "source": "workspace/SOUL.md" }, + "IDENTITY.md": { "source": "workspace/IDENTITY.md" }, + "TOOLS.md": { "source": "workspace/TOOLS.md" }, + "HEARTBEAT.md": { "source": "workspace/HEARTBEAT.md" } + }, + "files": [ + { + "source": "workspace/reference/triage-policy.md", + "path": "reference/triage-policy.md" + } + ] + }, + "packages": [ + { + "kind": "skill", + "source": "clawhub", + "ref": "@acme/issue-triage-playbook", + "version": "1.4.0" + }, + { + "kind": "plugin", + "source": "clawhub", + "ref": "@acme/github-actions", + "version": "2.1.0" + } + ], + "mcpServers": { + "github-triage-github": { + "command": "npx", + "args": ["-y", "@acme/github-mcp@3.4.1"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + }, + "toolFilter": { + "include": ["issues_list", "issues_get", "issues_comment"], + "exclude": ["repository_delete", "repository_admin_*"] + }, + "timeout": 30, + "connectTimeout": 10 + } + }, + "cronJobs": [ + { + "id": "weekday-triage", + "name": "Weekday GitHub triage", + "schedule": { + "cron": "0 9 * * 1-5", + "timezone": "America/New_York" + }, + "session": "isolated", + "message": "Review new GitHub issues and prepare a concise triage summary.", + "delivery": { + "mode": "announce", + "channel": "last" + } + } + ] +} +``` + +The schema version 1 field set, validation rules, JSON representation, and +`CLAW.md` envelope are normative for the experimental implementation. +Implementation slices may land separately behind the experimental gate, but a +producer or consumer must not claim schema v1 conformance until it implements +the complete grouped data model. Version 1 is strict: new portable fields, +semantic changes, and ownership changes require a new schema version so +existing consumers never interpret or silently discard an unknown declaration. + +Unknown fields fail closed. Implementations must not silently drop a declared +component and still call the agent complete. + +### Agent settings boundary + +Portable agent settings describe the job and its safe operating posture. The +initial allowlist should be drawn from existing OpenClaw agent configuration and +can include: + +- `id`, `name`, and `description`; +- agent identity presentation; +- group-chat mention patterns; +- sandbox boundaries; +- tool allow and deny policy; +- heartbeat behavior; +- human-delay behavior. + +The following remain operator controlled and are rejected in a Claw manifest: + +- model, provider, thinking level, and runtime implementation; +- API keys, OAuth state, credentials, or secret values; +- channel account ids, group ids, and bindings; +- default-agent selection and global `agents.defaults`; +- `agent.skills` allowlists; +- arbitrary config fragments or unknown future agent fields. + +The generated `agents.list[]` entry inherits operator defaults. Add appends one +entry and does not rewrite existing list members or defaults. + +For example, adding the illustrative manifest above with local agent id +`github-triage` appends an agent entry while preserving the operator's current +defaults and agents: + +```jsonc +{ + "agents": { + "defaults": { + // Existing operator-owned defaults remain unchanged. + }, + "list": [ + { + "id": "main", + "default": true + }, + { + "id": "github-triage", + "name": "GitHub Triage", + "description": "Reviews incoming GitHub issues and prepares a daily triage summary.", + "workspace": "~/.openclaw/workspace-github-triage", + "identity": { + "name": "Triage", + "emoji": "🔎" + }, + "groupChat": { + "mentionPatterns": ["@triage", "@github-triage"] + }, + "sandbox": { + "mode": "all", + "scope": "agent", + "workspaceAccess": "rw" + }, + "tools": { + "allow": ["read", "write", "edit", "web_fetch", "memory_search", "memory_get"], + "deny": ["exec", "browser", "nodes"] + }, + "heartbeat": { + "every": "30m", + "activeHours": { + "start": "08:00", + "end": "18:00" + }, + "lightContext": true, + "isolatedSession": true, + "skipWhenBusy": true, + "timeoutSeconds": 120 + }, + "humanDelay": { + "mode": "natural" + } + } + ] + }, + "plugins": { + "entries": { + "github-actions": { + "enabled": true + } + } + }, + "mcp": { + "servers": { + "github-triage-github": { + "command": "npx", + "args": ["-y", "@acme/github-mcp@3.4.1"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } + } +} +``` + +The installed skill lives under the new workspace's skill root. The cron job is +stored separately by the Gateway scheduler with `agentId: "github-triage"`; it +does not become an `openclaw.json` field. + +### Workspace semantics + +Every added Claw receives a new workspace. By default OpenClaw derives a path +from the final local agent id, for example +`~/.openclaw/workspace-github-triage`. The resolved path must not already be an +existing agent workspace or a Claw-managed workspace. + +`workspace.bootstrapFiles` names canonical OpenClaw files. The initial keys are +`AGENTS.md`, `SOUL.md`, `IDENTITY.md`, `TOOLS.md`, and `HEARTBEAT.md`. Supporting +content belongs in `workspace.files` with explicit package-relative source and +workspace-relative destination paths. + +All paths must remain within the unpacked Claw package or the new agent +workspace after realpath resolution. Symlink, hardlink, device-file, oversized, +and traversal escapes fail closed. The dry-run shows each source, destination, +digest, and action. + +Because add always targets a new workspace, v1 does not need general patch or +merge modes. Any unexpected existing destination is a collision and blocks add. +Update may replace an unchanged Claw-managed file, but it preserves local edits +and reports them as manual conflicts. + +### Package semantics + +`packages` contains only actual installable `skill` and `plugin` packages. +Every package is required. A blocked source, failed safety check, unavailable +exact version, or unsupported source blocks the complete add. + +Skill packages install into the new agent workspace through existing skill +installers. They are discovered from the workspace normally. Add must not set +`agents.list[].skills`. + +Plugin packages install through existing plugin installers and safety checks. +Plugin artifacts can be shared with direct user installs or other Claws. Claw +provenance is explanation and dependency metadata, not an uninstall lock. +Shared skill artifacts and plugins are referenced resources even when add +introduced them. A skill directory materialized exclusively in the Claw's +workspace is managed as part of that workspace. By default, removing a Claw +releases dependency edges and retains shared artifacts. + +The remove plan must offer explicit cleanup choices for referenced artifacts: + +1. `retain` releases only this Claw's dependency edge and is the default. +2. `remove-if-unused` invokes the canonical artifact lifecycle only when no + other Claw dependency edge or known non-Claw owner remains and the artifact + is complete, unchanged, and unambiguous. +3. `remove-selected` invokes canonical removal for artifacts explicitly chosen + by the operator. It must show every known affected Claw and direct owner and + require stronger confirmation when dependencies remain. + +These choices are bound into the integrity-checked remove plan. A failed or +declined canonical uninstall does not erase the resource's cleanup state. +Reference discovery belongs to the shared package lifecycle owner used by CLI, +Gateway, and Control UI uninstall entry points; a Claw command must not bypass +the same warnings by reimplementing removal. A dependency edge is neither a +hidden refcount lock nor authority to override a confirmed operator uninstall. +This includes the Control UI plugin-management work in +[openclaw/openclaw#103176](https://github.com/openclaw/openclaw/pull/103176): +its install, enablement, disablement, and uninstall controls remain plugin lifecycle +operations, while Claws contribute references and shared uninstall warnings. + +Update installs the exact target package version before advancing Claw +provenance. Removing a package from a Claw releases only that Claw's reference. +A global plugin must not be replaced when another installed Claw is pinned to a +different version. Package installers do not currently provide a general +artifact rollback contract, so a later update failure after installation is +reported as partial even when Claw reference provenance can be compensated. + +### MCP server semantics + +`mcpServers` maps stable server names to a reviewed portable subset of the +existing OpenClaw MCP server config shape. Add writes those declarations to +top-level `mcp.servers`; they are not nested inside the generated agent entry. +The initial subset supports both local stdio servers (`command`, `args`, and +related process settings) and remote servers (`url`, `sse` or +`streamable-http` transport, and credential-free OAuth intent). It does not +carry arbitrary authorization headers, bearer tokens, client secrets, or +completed OAuth state. + +Server-name collisions fail unless the existing canonical config is identical +and a referenced dependency edge can be recorded without taking over unrelated +state. A newly created, collision-free MCP declaration is managed by the Claw; +an identical pre-existing declaration is referenced. Both cases use the same +canonical MCP config path, plan preview, capability consent, drift checks, and +operator-selected cleanup rules as other resources. Environment +placeholders such as `${GITHUB_TOKEN}` remain references. Resolved secret values +must never be stored in the manifest, plan, logs, or provenance. Provenance uses +a canonical redacted digest sufficient for drift detection. Remote OAuth and +other credential completion is an operator-owned local step after add. The +Control UI may present curated MCP suggestions, but their presentation identity +is not a Claw package dependency, hosted-feed entry, or provenance key. + +### Heartbeat and cron semantics + +Heartbeat and cron jobs are distinct existing OpenClaw concepts: + +- `agent.heartbeat` controls when and how the new agent wakes. +- `workspace.bootstrapFiles["HEARTBEAT.md"]` contains what the agent checks. +- `cronJobs` contains exact scheduled jobs stored by the Gateway scheduler. + +Every created cron job is pinned to the final local agent id regardless of +whether the manifest id or `--agent-id` override supplied it. Cron ids must be +unique within the Claw and must not overwrite existing scheduler records. +Dry-run shows cadence, timezone, session mode, message/action, delivery, and the +derived `agentId`. Mutating add creates cron jobs only after the agent and +workspace are ready, and provenance stores stable scheduler ids for status, +update, disable, and removal. + +Channel delivery settings may name portable modes such as `last`, but a Claw +does not embed account ids, group ids, credentials, or bindings. Operators bind +the new agent to local channels separately. + +### CLI and lifecycle + +#### Experimental incubation gate + +While this RFC remains draft, every Claws CLI surface is gated behind the +process-level opt-in `OPENCLAW_EXPERIMENTAL_CLAWS=1`. + +When the gate is absent or false: + +- OpenClaw does not register the `claws` command; +- Claws do not appear in default help, shell completions, or onboarding; +- no background service, update flow, or Gateway startup path reads or applies + Claw state; +- encountering Claw package metadata through an ordinary install path does not + implicitly enable the experiment. + +The hosted experimental guide is intentionally public and may appear in the +documentation navigation while the local command is disabled. Static hosted +documentation cannot observe a process environment variable, so it labels the +feature experimental and shows the opt-in explicitly. Public documentation is +not a stability promise and does not enable any local runtime surface. + +The gate is intentionally an environment opt-in rather than a persisted config +field. Internal launchers, test lanes, and controlled deployments can enable it +for a process, but users do not acquire a durable experimental setting that is +silently carried into later releases or fleet config. + +When enabled, text-mode commands print a concise experimental compatibility +warning before mutation, and machine-readable results include +`stability: "experimental"` plus their exact output schema version. During the +draft period, the manifest schema, CLI flags, JSON result shapes, and SQLite +tables may change without backward-compatibility guarantees. Destructive +commands still require their normal explicit consent; the experimental gate is +not consent and does not weaken any safety check. + +Removing the gate is a separate maintainer decision after this RFC is accepted. +That graduation PR must define released migration behavior, stable CLI and JSON +contracts, documentation, and compatibility policy. Shipping experimental code +does not itself establish those contracts. + +The public CLI is: + +```bash +openclaw claws inspect +openclaw claws add --dry-run --json +openclaw claws add [--agent-id ] [--workspace ] --yes --plan-integrity +openclaw claws status [claw-or-agent] +openclaw claws update [--from ] --dry-run --json +openclaw claws update [--from ] --yes --plan-integrity +openclaw claws remove --dry-run --json [cleanup selection] +openclaw claws remove --yes --plan-integrity [cleanup selection] +openclaw claws export --out +``` + +`inspect` validates package metadata and the grouped manifest without reading or +mutating local lifecycle state. `add --dry-run` resolves the final agent id, +workspace, packages, MCP servers, and cron jobs and emits the complete action +plan. `add` without `--dry-run` requires `--yes` and the exact +`--plan-integrity` digest from that dry run. Update uses the source recorded in +provenance unless `--from` explicitly overrides it. Remove retains referenced +resources by default; `--remove-unused`, repeatable `--remove-referenced`, and +`--force-referenced` select stronger cleanup in both preview and mutation so +the choice is included in the plan digest. `--yes` alone never broadens a plan. + +Add ordering is transactional where owner APIs permit it and resumable where +external installers or the scheduler cannot share one transaction: + +1. Validate package metadata and manifest. +2. Resolve exact dependencies and run install safety checks. +3. Resolve the final unused agent id and workspace. +4. Preflight all config, file, MCP, and cron collisions. +5. Create the agent entry and workspace state. +6. Write bootstrap and supporting files. +7. Install workspace skills and plugin dependencies. +8. Configure MCP servers. +9. Create agent-pinned cron jobs. +10. Persist one complete apply record and per-resource provenance. + +Any failure stops later phases. Pending provenance is written before external +mutation and successful resources are recorded immediately. Safe local +pre-commit work may be compensated, but a completed or uncertain owner mutation +is retained for deterministic resume, doctor, or remove rather than hidden by a +best-effort rollback. The result distinguishes complete, partial, and failed +adds; it never reports a partial agent as successfully added. + +### Provenance and local state + +Claw lifecycle state belongs in OpenClaw's shared SQLite state database, not in +the user config file and not only in marker files inside the workspace. + +The installed record must include: + +- package identity, version, integrity, source, and source byte length; +- final local agent id and workspace root; +- generated agent config digest and owned field paths; +- managed workspace paths and content digests; +- exact skill and plugin artifact identities, managed or referenced + relationship, resource origin, and current independent ownership; +- MCP server names, managed or referenced relationship, resource origin, + current independent ownership, and canonical redacted config digests; +- cron job ids and scheduler record ids; +- add/update timestamps and actor or caller when available; +- partial-operation diagnostics and cleanup state. + +Status and doctor read this ledger to report missing agents, workspace drift, +modified files, missing dependencies, changed MCP config, missing or changed cron +jobs, and orphaned partial state. + +### Update, remove, and export + +Update always targets the installed agent created by the Claw. It never changes +another agent merely because a target manifest now uses the same id. Update has +a read-only plan and a separately consented apply. + +Update may add or change portable agent fields, files, package dependencies, MCP +servers, and cron jobs owned by the installed Claw. Local modifications become +manual conflicts. Operator defaults, models, providers, credentials, bindings, +and unrelated config remain untouched. + +Consented update rebuilds the read-only plan immediately before mutation. Each +owner uses its strongest available concurrency boundary: workspace content +digests, expected MCP config values, stable cron declaration keys and scheduler +ids, exact package refs, and agent/root provenance compare-and-swap checks. +Workspace checks include expected file presence as well as content. Before an +external package installer runs, OpenClaw atomically replaces the expected +package reference with a pending ownership claim; concurrent ownership changes +abort before installation. Once the installer boundary is crossed, failure +retains pending or failed provenance because the artifact outcome may be +uncertain. +Completed owners compensate in reverse order only when the canonical owner can +prove the inverse operation is safe. A thrown config or Gateway call has an +uncertain commit outcome, and an installed package artifact cannot be assumed +rolled back merely because its reference was restored. Pending owner provenance +and a partial root status are retained in these cases so status, doctor, and a +retry can reconcile the actual state rather than claiming cross-owner atomicity. +Removing a package declaration during update releases the Claw dependency edge; +artifact uninstall is a separately planned remove operation, never an update +side effect. + +Remove first produces a plan. Managed resources are selected for cleanup by +default: it removes agent-pinned cron jobs, unchanged Claw-managed MCP +declarations and workspace files, and the Claw-created agent through their +canonical owner lifecycles. Referenced packages and MCP declarations are +retained by default while their dependency edges are released. The operator may +instead select eligible referenced resources for `remove-if-unused`, or select +specific referenced resources for canonical removal after reviewing dependency +warnings. Locally modified files, unrelated MCP servers, channel bindings, and +operator state remain outside Claw cleanup. Failed cleanup remains visible in +status and doctor. + +Export is agent-centric. It exports only portable state belonging to the chosen +agent: supported agent settings, selected workspace bootstrap/supporting files, +installed skill/plugin refs, matching MCP declarations, and agent-pinned cron +jobs. It excludes secrets, resolved environment values, models/providers, +bindings, sessions, logs, caches, and unrelated global state. Package output +uses `package.json` for identity, `CLAW.md` for the grouped manifest, and +confined sidecars. Readers continue to accept the equivalent grouped JSON +manifest. + +### Feeds, catalogs, and ClawHub + +RFC 0009 feeds remain the conceptual discovery and policy layer. A feed may +expose a Claw package, pin an exact version, recommend or block it, and +independently block or substitute package dependencies. Approval of the Claw +does not transitively approve its skills or plugins. While Claws are +experimental, ClawHub uses a separate gated Claw feed parser, serializer, feed +id, and route rather than adding `type: "claw"` to RFC 0009's stable plugin and +skill feed schema version 1. + +That feed boundary is intentionally narrower than the complete Control UI +experience. Hosted feeds currently provide official plugin and skill catalog +entries. Installed MCP servers come from local `mcp.servers`, while the Control +UI's suggested MCP connectors are a separately curated presentation surface. +Claws use the first mechanism to resolve exact plugin and skill package inputs, +and use direct portable MCP declarations for the second kind of capability. +They do not create a third connector registry or infer a stable connector +identity from a UI suggestion. + +ClawHub owns authenticated publication, package ownership, search/detail/API +surfaces, hosted feed export, and authoring guidance. OpenClaw owns manifest +validation, planning, local mutation, provenance, and lifecycle behavior. Both +must share the schema and fixtures rather than maintain divergent validators. + +### Safety and security + +- Agent-id and workspace collisions fail closed. +- Add never mutates an existing agent. +- Unknown fields or unsupported declared components fail closed. +- All package dependencies pass existing source, integrity, compatibility, and + install safety checks. +- Workspace package reads and destination writes use rooted, symlink-safe, + hardlink-safe file APIs with size limits. +- Secrets and resolved environment values never enter plans or provenance. +- MCP config writes use validated, concurrent-write-safe config APIs. +- Cron jobs require explicit consent, visible cadence/action previews, stable + ownership, live-definition revalidation, and disable/remove handles. +- Config mutation preserves `agents.defaults`, existing `agents.list[]` entries, + channel bindings, and unrelated plugin/MCP settings. +- Partial adds persist enough state for diagnosis and cleanup. +- Update and remove revalidate expected presence, content/config digests, and + provenance ownership at the actual mutation boundary. +- A plan that adds executable code, an MCP execution or network surface, + plugin/tool access, or recurring work must identify that capability + escalation in a distinct machine-readable record and human-readable plan + section. OpenClaw may use one confirmation token only when + `--plan-integrity` binds the exact separately disclosed capability set as + well as ordinary content reconciliation. Other hosts may require a separate + dialog or aggregate those records before mutating multiple agents. +- ClawHub trust warnings and resolved dependency identity are part of the + separately disclosed capability effect and plan integrity. The Claw CLI's + exact plan confirmation may acknowledge that warning; an internal + `acknowledge` parameter must not make the warning disappear from preview. +- Claws do not introduce capability-specific resource quotas. Existing + canonical owner limits apply. Claw manifests are limited to 1 MiB and package + metadata to 256 KiB; extraction, managed workspace, and plan limits remain + parser and resource-safety policy. + +## Rationale + +The one-Claw-one-new-agent model gives the lifecycle one understandable unit of +ownership while continuing to delegate files, packages, MCP configuration, and +scheduled work to their existing OpenClaw owners. Grouped schema fields make +those boundaries reviewable; plan-first mutation, provenance, and conservative +cleanup make composition safer than an opaque setup script or whole-instance +export. The tradeoff is a broader lifecycle than an ordinary package manager, +which is why the RFC uses `add`/`remove`, explicit partial outcomes, and an +experimental gate rather than promising cross-owner atomicity. + +## Compatibility and migration + +Claws are additive. Existing agents, skills, plugins, MCP servers, cron jobs, +feeds, and plugin bundles continue to work without becoming Claws. + +The earlier prototype used `openclaw.claw.v1`, a flat `entries[]` list, and +`claws apply` against a caller-selected workspace. That prototype is not the +accepted public compatibility contract. Before any implementation PR is made +ready, it must be restacked around the grouped schema and one-new-agent +invariant. Prototype SQLite tables may be discarded or migrated during the +draft phase; no released migration promise exists until the RFC is accepted. + +## Rollout plan + +Implementation should widen the trust boundary in reviewable slices: + +1. **Schema and read-only plan.** Parse package metadata and grouped manifests; + implement `inspect` and `add --dry-run`; prove agent/workspace collision + behavior and complete blockers without mutation. +2. **Agent and workspace creation.** Add one `agents.list[]` entry, derive a new + workspace, preserve defaults and existing agents, and persist the root apply + record. +3. **Workspace bootstrap and supporting files.** Add confined file writes, + managed hashes, partial-failure provenance, and local-edit protection. +4. **Skill and plugin packages.** Reuse existing installers, install skills into + the new workspace, preserve artifact ownership boundaries, and warn on direct + uninstall when Claws reference an artifact. +5. **MCP servers.** Add validated top-level MCP configuration, collision checks, + redacted digest provenance, status, and cleanup. +6. **Heartbeat and cron jobs.** Apply portable heartbeat config and create + scheduler records pinned to the new agent id with status/disable/remove proof. +7. **Status, doctor, and remove.** Diagnose complete and partial agents, drift, + orphaned resources, and conservative cleanup. +8. **Update planning and apply.** Reconcile only the installed Claw-owned agent + and resources, separating read-only planning from consented mutation. +9. **Export and round trip.** Export a selected agent to package metadata, + grouped manifest, and safe sidecars; prove export-to-add in a fresh state dir. +10. **ClawHub publication and feeds.** Share schema fixtures, publish a package, + expose it through hosted feeds, and prove source resolution and add dry-run. + +### Current OpenClaw implementation stack + +The experimental implementation is one RFC plus twelve ordered OpenClaw PRs. Each +implementation PR is based on the preceding head so reviewers can evaluate one +ownership boundary at a time: + +1. [#101328](https://github.com/openclaw/openclaw/pull/101328) - grouped schema, + inspect, and read-only add planning. +2. [#101755](https://github.com/openclaw/openclaw/pull/101755) - new agent, + workspace root, and root install provenance. +3. [#101973](https://github.com/openclaw/openclaw/pull/101973) - managed + workspace bootstrap and supporting files. +4. [#102228](https://github.com/openclaw/openclaw/pull/102228) - exact ClawHub + skill/plugin installation and shared uninstall-reference warnings. +5. [#102296](https://github.com/openclaw/openclaw/pull/102296) - plan-first + status and conservative remove. +6. [#102306](https://github.com/openclaw/openclaw/pull/102306) - agent-centric + grouped export. +7. [#102383](https://github.com/openclaw/openclaw/pull/102383) - Gateway-owned + cron jobs and scheduler provenance. +8. [#102406](https://github.com/openclaw/openclaw/pull/102406) - stdio and remote + MCP ownership, including credential-free OAuth intent. +9. [#102427](https://github.com/openclaw/openclaw/pull/102427) - lifecycle and + drift diagnostics. +10. [#102959](https://github.com/openclaw/openclaw/pull/102959) - read-only + grouped update planning. +11. [#102982](https://github.com/openclaw/openclaw/pull/102982) - consented + grouped update apply and compensation. +12. [#111391](https://github.com/openclaw/openclaw/pull/111391) - thin + `CLAW.md` YAML-frontmatter input/export adaptation with grouped JSON read + compatibility and no separate lifecycle behavior. It supersedes #106888, + which was merged only into an obsolete stack head. + +Public documentation follows the same staged boundary as the implementation. +#101328 introduces the experimental guide, navigation, opt-in, schema, inspect, +and add preview. Each later PR extends that guide only with the command or +resource behavior implemented at that stage. #111391 adds only `CLAW.md` +authoring and canonical export documentation. At every intermediate stack head, +the guide must describe no later command or ownership behavior. + +These PRs replace the old workspace-apply prototype rather than +extending its compatibility contract. Every experimental CLI PR remains behind +`OPENCLAW_EXPERIMENTAL_CLAWS=1`; command registration, help, completion, and +direct-handler tests must prove the disabled state as well as the enabled state. + +### Current ClawHub implementation stack + +ClawHub follows the OpenClaw schema and lifecycle contract in four ordered PRs: + +1. [#3089](https://github.com/openclaw/clawhub/pull/3089) - shared manifest + validation, derived summaries, and storage data model. Existing generic + publication remains closed to Claws. +2. [#3090](https://github.com/openclaw/clawhub/pull/3090) - guarded publication, + package ingestion, source-file checks, CLI authoring support, and author + guidance. It also owns the fail-closed public-read boundary while disabled + and strips full manifests from every public release serializer. Publication + retains the exact immutable artifact bytes and bounded summary, validates + every package path, requires exact manifest/source spelling, applies strict + UTF-8 and pre-parse size limits, and accepts Claw npm packs without requiring + a plugin manifest. +3. [#3091](https://github.com/openclaw/clawhub/pull/3091) - enabled search, + detail, and version APIs that expose only the latest or requested release's + bounded summary. +4. [#3092](https://github.com/openclaw/clawhub/pull/3092) - separately gated + hosted Claw feed with its own experimental wire contract, safe summaries, + and exact artifact digests, plus a repeatable published-package proof through + real OpenClaw add dry-run. The versioned route is gated before publication + lookup and has no ungated unversioned redirect. The proof bounds download, + entry count, per-file and aggregate expansion; rejects unsafe or colliding + paths, links, and special archive entries; and supports npm-pack and legacy + ZIP package roots. + +The #3092 proof is a registry-to-OpenClaw bridge: it selects an exact candidate +from the experimental Claw feed, verifies and extracts the artifact, then hands +the package directory to OpenClaw. It proves that the published package produces +a real non-mutating OpenClaw plan; native OpenClaw Claw-feed resolution remains +a separate dependent integration. + +The ClawHub runtime surfaces in this track require +`CLAWHUB_EXPERIMENTAL_CLAWS=1`. The deployment gate is independent of +`OPENCLAW_EXPERIMENTAL_CLAWS=1` in the OpenClaw client and is not a replacement +for explicit add/update consent. + +The experimental ClawHub contract accepts both `CLAW.md` and the equivalent +grouped JSON manifest behind `CLAWHUB_EXPERIMENTAL_CLAWS=1`; it does not add a +second format-specific gate. Search, detail, and feed APIs expose bounded +summaries and immutable artifact coordinates; the applying client reviews the +full declaration from the resolved artifact. + +## Acceptance criteria + +The RFC implementation is acceptable when tests and real CLI proof demonstrate: + +1. Inspect validates package identity and the grouped manifest without mutation. +2. Without `OPENCLAW_EXPERIMENTAL_CLAWS=1`, the `claws` command is unregistered, + absent from help and completions, and cannot be enabled by package content; + the public experimental guide remains non-executable documentation. +3. Add dry-run shows one new agent, one new workspace, every file/package/MCP/ + cron action, all collisions, and stable machine-readable blockers. +4. An existing agent id or workspace blocks add unless an explicit unused + override is supplied. +5. Add appends one agent without changing defaults or existing agents. +6. Canonical and supporting files are confined to the new workspace. +7. Skills install into that workspace without setting `agent.skills`. +8. Plugins use existing safety checks and preserve shared/direct ownership; + CLI, Gateway, and Control UI uninstall paths all emit Claw-reference warnings + through the shared lifecycle owner. +9. Portable stdio and remote MCP declarations write only validated top-level + config, store no secrets or completed OAuth state in provenance, and do not + depend on a feed-backed connector identity. +10. Cron jobs are scheduler records pinned to the final local agent id. +11. Any declared unsupported or blocked component fails the complete add. +12. Partial failures remain visible and cleanable; they are not reported as a + successfully added Claw. +13. Status and doctor explain agent, workspace, package, MCP, cron, and managed + file drift. +14. Update changes only Claw-owned state, preserves local/operator edits, + revalidates owner state before mutation, compensates only safely reversible + completed owners, retains uncertain provenance, and reports uncertain or + irreversible outcomes as partial. +15. Remove uses canonical owner lifecycles, selects managed resources for + cleanup, retains referenced resources by default, offers integrity-bound + `remove-if-unused` and explicitly selected referenced cleanup, warns about + every known affected Claw or direct owner, and preserves modified or + unrelated state. +16. Export emits `CLAW.md`, excludes secrets and operator runtime settings, + retains grouped JSON read compatibility, and can be added in a fresh state + directory as a new equivalent agent. +17. Feed approval does not bypass dependency policy or install safety checks. +18. Every implementation stage documents its newly available surface without + claiming commands or ownership behavior from a later stage. +19. Add and update plans disclose capability escalations separately from + ordinary content, include them in plan integrity, and reject mutation when + the reviewed capability set changes. + +## Unresolved questions + +- Before removing the experimental gate, should `CLAW.md` remain the default + authoring/export representation or should export return to grouped JSON? +- What exact default workspace naming rule should resolve cross-platform path + and case-folding collisions? +- Should ordinary `agents delete` eventually delegate attached-Claw recurring + work cleanup, or remain distinct from the provenance-aware `claws remove` + lifecycle? +- Should a future audit/history feature retain removed Claw tombstones? V1 keeps + current ownership and incomplete recovery state only. +- Which cron delivery modes are portable without embedding local channel + bindings? +- What package transports should mutating v1 support beyond ClawHub and local + development packages? +- What is the minimum released SQLite migration contract before Claws leave + draft status? +- How should OpenClaw and ClawHub publish and version one shared schema and + fixture suite? diff --git a/rfcs/0016/claw-md-v1-spec.md b/rfcs/0016/claw-md-v1-spec.md new file mode 100644 index 00000000..0e4f395e --- /dev/null +++ b/rfcs/0016/claw-md-v1-spec.md @@ -0,0 +1,448 @@ +# CLAW.md v1 Specification + +This document is the implementer-facing manifest specification for RFC 0016, +Claws. The RFC explains the product model, ownership boundaries, lifecycle, and +rollout plan. This file defines the schema version 1 data contract shared by +OpenClaw and Claw registries and its human-readable `CLAW.md` envelope. + +Status: experimental draft, tied to RFC 0016. + +## Incubation Status + +The experimental implementation reads `CLAW.md` and equivalent grouped JSON, +and exports `CLAW.md`. Both forms use the existing +`OPENCLAW_EXPERIMENTAL_CLAWS=1` gate; there is no format-specific flag. + +`CLAW.md` is intentionally a thin serialization layer over the grouped schema. +It does not define separate lifecycle, ownership, provenance, or capability +semantics and introduces no new runtime dependency. Until the Claws gate is +removed, maintainers may revise or remove this envelope without preserving it +as a stable compatibility contract. Feedback remains welcome on the YAML +frontmatter boundary, Markdown-body role, portability, and authoring ergonomics. + +## Scope + +This specification defines: + +- how a `CLAW.md` document carries a machine-readable Claw manifest; +- the equivalent JSON representation; +- the grouped schema version 1 fields; +- strict parsing, defaults, and rejection behavior; +- portable path, package, MCP, and cron declarations; +- local prerequisite and diagnostic requirements; +- producer and consumer conformance requirements. + +This specification does not define: + +- package identity, archive layout, publication, or registry APIs; +- local add, update, remove, or provenance storage internals; +- credentials, channel bindings, models, providers, or completed OAuth state; +- a whole-instance export format; +- a generic harness-neutral runtime API. + +The enclosing package contract is defined by +[`claw-package-v1-spec.md`](claw-package-v1-spec.md). + +## Design Goals + +`CLAW.md` is intended to be understandable in a code review while remaining a +strict input to lifecycle tooling. Its Markdown body can explain the agent to a +human. Its YAML frontmatter is the only executable declaration. + +The same data model may also be represented as JSON. Markdown and JSON are two +serializations of one schema, not different capability levels. + +## File Identification and Encoding + +The canonical Markdown filename is `CLAW.md`. Consumers identify that filename +case-insensitively when selecting the Markdown parser. Other package-selected +manifest filenames are parsed as JSON. + +A `CLAW.md` file must be UTF-8 text. Consumers must accept zero or one leading +UTF-8 byte-order mark and must reject additional byte-order marks. The accepted +byte-order mark is ignored for frontmatter matching, but the original file bytes +remain part of every package or source integrity digest. + +## Document Envelope + +A `CLAW.md` document has this shape: + +```markdown +--- +schemaVersion: 1 +agent: + id: github-triage +--- + +# GitHub Triage + +This Claw creates an agent that triages GitHub issues. +``` + +The following rules apply: + +1. After an optional leading byte-order mark, the first line must be exactly + `---`. +2. The opening delimiter must be followed by LF or CRLF. +3. The YAML frontmatter ends at the next line containing exactly `---`. +4. The closing delimiter must be followed by LF, CRLF, or end of file. +5. The Markdown body after the closing delimiter is documentation only. A + consumer must not derive runtime behavior, package dependencies, policy, or + lifecycle actions from it. +6. Producers should include a short heading and description in the Markdown + body, but consumers must accept an empty body. + +## YAML Conversion + +Consumers must parse the frontmatter as one YAML 1.2 document using the YAML +1.2 Core Schema, then convert it to a JSON-compatible value before manifest +schema validation. A consumer must not apply YAML 1.1 scalar resolution; for +example, the unquoted v1 enum value `off` is a string, not a boolean. + +Consumers must reject: + +- malformed YAML; +- duplicate mapping keys; +- a frontmatter value that cannot be converted to JSON-compatible data; +- multiple YAML documents; +- anchors, aliases, merge keys, and explicit YAML tags; +- non-string mapping keys, non-finite numbers, and other values that have no + unambiguous JSON representation; +- any value that fails the strict manifest schema below. + +Consumers must not perform environment expansion, shell interpolation, +template evaluation, Markdown execution, or implicit package resolution while +parsing `CLAW.md`. Environment placeholders are retained as literal strings and +validated only where the schema permits them. + +## Top-Level Manifest + +The top-level value must be an object with these fields: + +| Field | Type | Required | Semantics | +| --- | --- | --- | --- | +| `schemaVersion` | integer | Yes | Must be exactly `1`. | +| `agent` | object | Yes | Portable configuration for the one new agent. | +| `workspace` | object | No | Bootstrap and supporting files. Defaults to empty. | +| `packages` | array | No | Exact skill and plugin dependencies. Defaults to empty. | +| `mcpServers` | object | No | Portable MCP declarations keyed by server name. Defaults to empty. | +| `cronJobs` | array | No | Agent-pinned scheduled work. Defaults to empty. | + +Unknown top-level or nested fields must be rejected. A producer must not use an +unknown field as a forward-compatible extension point. + +The manifest does not declare `managed`, `referenced`, ownership, uninstall, or +cleanup fields. The applying harness derives each resource relationship from +its kind and canonical owner state as specified by the package lifecycle. This +prevents package authors from claiming deletion authority over pre-existing or +shared host resources. Operator-selected referenced cleanup is remove-plan +input, not portable package content. + +## Agent + +`agent.id` is required. It must start with a lowercase ASCII letter, contain +only lowercase ASCII letters, digits, `_`, or `-`, and contain at most 64 +characters. It is the default local id; add still fails if that id or its +derived workspace is already in use. + +The portable agent object is: + +| Field | Type | Required | Constraints | +| --- | --- | --- | --- | +| `id` | string | Yes | Agent-id syntax above. | +| `name` | string | No | Non-empty after trimming. | +| `description` | string | No | Non-empty after trimming. | +| `identity.name` | string | No | Non-empty after trimming. | +| `identity.theme` | string | No | Non-empty after trimming. | +| `identity.emoji` | string | No | Non-empty after trimming. | +| `identity.avatar` | string | No | Non-empty portable avatar described below. | +| `groupChat.mentionPatterns` | string array | No | At least one non-empty string when present. | +| `sandbox.mode` | enum | No | `off`, `non-main`, or `all`. | +| `sandbox.scope` | enum | No | `session`, `agent`, or `shared`. | +| `sandbox.workspaceAccess` | enum | No | `none`, `ro`, or `rw`. | +| `tools.allow` | string array | No | At least one non-empty string when present. | +| `tools.deny` | string array | No | At least one non-empty string when present. | +| `heartbeat` | object | No | Exact portable heartbeat object below. | +| `humanDelay` | object | No | Exact portable human-delay object below. | + +All objects are strict. Consumers may accept empty optional objects, but +canonical producers must omit an optional object when none of its members are +present. + +`heartbeat` may contain only: + +| Field | Type | Constraints | +| --- | --- | --- | +| `every` | string | A non-negative OpenClaw duration using `ms`, `s`, `m`, `h`, or `d`; composite forms such as `1h30m` are allowed and a bare number means minutes. | +| `activeHours.start` | string | `HH:MM` in 24-hour form from `00:00` through `23:59`. | +| `activeHours.end` | string | `HH:MM` in 24-hour form from `00:00` through `24:00`; no other `24:xx` value is valid. | +| `activeHours.timezone` | string | Non-empty IANA timezone recognized by the scheduler. | +| `lightContext` | boolean | No additional constraint. | +| `isolatedSession` | boolean | No additional constraint. | +| `skipWhenBusy` | boolean | No additional constraint. | +| `timeoutSeconds` | integer | Greater than zero. | + +`humanDelay` may contain only `mode`, `minMs`, and `maxMs`. `mode`, when +present, is `off`, `natural`, or `custom`. The millisecond values are optional +non-negative integers. Version 1 imposes no relationship between them; runtime +behavior uses the declared values only when the selected mode requires them. + +`identity.avatar` may be an image data URL no larger than 2 MiB decoded or +2,796,230 characters encoded, or a workspace-relative path with a `.png`, +`.jpg`, `.jpeg`, `.gif`, `.webp`, or `.svg` extension. Remote URLs are not +portable v1 avatar values because their bytes are mutable and outside package +integrity. A workspace-relative avatar must exactly match a destination +declared in `workspace.files`. Its package source is then subject to the same +existence, containment, size, copy, digest, provenance, and drift rules as every +other managed workspace file. Consumers must reject an undeclared local avatar +path. + +The manifest must not declare models, providers, thinking levels, credentials, +channel accounts, channel bindings, local default selection, or an existing +workspace path. Those remain operator-owned. + +## Workspace + +`workspace.bootstrapFiles` maps canonical OpenClaw filenames to package +sources. The only v1 keys are: + +- `AGENTS.md` +- `SOUL.md` +- `IDENTITY.md` +- `TOOLS.md` +- `HEARTBEAT.md` + +Each value has one required `source` field. `workspace.files` contains objects +with required `source` and `path` fields. `source` is relative to the package +root; `path` is relative to the new agent workspace. + +Paths must be non-empty and relative. They must not contain absolute roots, +drive prefixes, empty segments, `.` segments, or `..` segments after `\` is +normalized to `/`. Package ingestion and local application must additionally +enforce realpath containment and reject unsafe filesystem objects as described +by the package specification. + +No two declarations may target the same workspace destination after `\` to `/` +normalization, Unicode NFC normalization, and locale-independent case folding. +Consumers must use that normalized value only as a collision key; they must +preserve the declared spelling when materializing an accepted path. A supporting +file must not target a canonical bootstrap filename already declared in +`bootstrapFiles` under the same comparison. + +## Packages + +Each `packages` entry has this exact shape: + +```yaml +- kind: skill + source: clawhub + ref: "@acme/issue-triage-playbook" + version: 1.4.0 +``` + +| Field | Type | Required | Semantics | +| --- | --- | --- | --- | +| `kind` | enum | Yes | `skill` or `plugin`. | +| `source` | enum | Yes | `clawhub` in schema version 1. | +| `ref` | string | Yes | Canonical immutable package coordinate assigned by the selected source. | +| `version` | string | Yes | Exact SemVer 2.0.0 version; ranges, tags, a leading `v`, and non-canonical numeric identifiers are forbidden. | + +The source's canonicalization rules produce the identity key for `ref`; display +slugs and aliases are not identity. The tuple `(kind, source, canonical ref)` +must be unique within a manifest. Every package is required. The declaration +does not bypass source policy, scanning, compatibility checks, or the existing +skill/plugin installer. + +## MCP Servers + +`mcpServers` is keyed by a stable local server name using the same identifier +rules as `agent.id`. + +A stdio server requires `command` and may declare: + +- `transport: stdio`; +- `args` as an array of non-empty strings; +- `env` as a map whose values are literal `${ENV_VAR}` references; +- `toolFilter.include` and `toolFilter.exclude` arrays; +- finite positive `timeout` and `connectTimeout` values in seconds. + +`command` and `args` are an executable plus literal argument vector. Consumers +must not pass them through a shell or perform variable, glob, home-directory, or +command substitution. Inspection and add must not launch the server. A package +manager command that names a downloadable artifact must use an exact immutable +version; a floating tag or range blocks the plan. + +Environment keys must match `[A-Za-z_][A-Za-z0-9_]*`. Each value must match +`${[A-Z_][A-Z0-9_]*}` exactly. Literal secret values are forbidden. The applying +client must evaluate keys through its canonical spawned-process environment +safety policy; a blocked key blocks the Claw plan rather than being silently +dropped. + +A remote server requires a URL and `transport` equal to `sse` or +`streamable-http`. The URL must use HTTPS, except that HTTP is allowed when the +hostname is exactly `localhost`, `127.0.0.1`, or `[::1]`. User information and +fragments are forbidden. A remote server may declare `auth: oauth`, tool +filters, and finite positive timeouts in seconds. It must not carry +authorization headers, bearer tokens, client secrets, or completed OAuth state. + +The stdio and remote shapes are mutually exclusive. A stdio declaration must +not contain `url` or `auth`; a remote declaration must not contain `command`, +`args`, or `env`. A consumer must reject a mixed declaration rather than choose +one transport by field order or precedence. + +`toolFilter.include` and `toolFilter.exclude`, when present, each contain at +least one unique non-empty exact tool name or simple `*` glob. A simple glob is +matched against the complete tool name, treats `*` as the only wildcard, and +treats every other character literally; `?`, character classes, and path +semantics are not supported. `include` first limits the discovered set and +`exclude` then removes matches, so exclusion wins when both match. Duplicate +filter entries must be rejected after exact string comparison. + +Unresolved environment references and `auth: oauth` are local prerequisites, +not embedded credentials. Dry-run must list their names and affected server +without resolving or printing secret values. Add may complete after safely +writing the declaration, but status must report the server as `requires-local- +configuration` until every required environment value exists and OAuth login, +when declared, is complete. An applied Claw is not necessarily ready to run. + +## Cron Jobs + +Each cron job contains: + +| Field | Type | Required | Semantics | +| --- | --- | --- | --- | +| `id` | string | Yes | Manifest-local stable id using agent-id syntax. | +| `name` | string | No | Display name. | +| `schedule.cron` | string | Yes | Valid cron expression. | +| `schedule.timezone` | string | Yes | Non-empty IANA timezone recognized by the scheduler. | +| `session` | enum | Yes | `main` or `isolated`. | +| `message` | string | Yes | Non-empty scheduled input. | +| `delivery.mode` | enum | No | `none` or `announce`. | +| `delivery.channel` | enum | No | `last` in schema version 1. | + +Cron ids must be unique. The lifecycle pins each created scheduler record to +the final local agent id; the manifest does not carry a channel account or +binding. + +`schedule.cron` must be a portable five-field minute/hour/day-of-month/month/ +day-of-week expression. Host-local timezone defaults are forbidden. `delivery` +may be omitted, may be `{ mode: none }`, or may be +`{ mode: announce, channel: last }`; `channel` is forbidden for `none` and +required for `announce`. Dry-run must identify that `last` resolves through +local channel state and does not embed a binding. + +## Complete Example + +```markdown +--- +schemaVersion: 1 +agent: + id: github-triage + name: GitHub Triage + description: Reviews incoming issues and prepares a daily summary. + tools: + allow: [read, write, web_fetch] + deny: [exec] + heartbeat: + every: 30m +workspace: + bootstrapFiles: + AGENTS.md: + source: workspace/AGENTS.md + SOUL.md: + source: workspace/SOUL.md + files: + - source: workspace/reference/triage-policy.md + path: reference/triage-policy.md +packages: + - kind: skill + source: clawhub + ref: "@acme/issue-triage-playbook" + version: 1.4.0 + - kind: plugin + source: clawhub + ref: "@openclaw/github" + version: 2.1.0 +mcpServers: + github: + command: npx + args: [--yes, "@acme/github-mcp@3.4.1"] + env: + GITHUB_TOKEN: "${GITHUB_TOKEN}" +cronJobs: + - id: daily-triage + schedule: + cron: "0 9 * * 1-5" + timezone: America/Los_Angeles + session: isolated + message: Review new issues and prepare the daily triage summary. + delivery: + mode: announce + channel: last +--- + +# GitHub Triage + +Adds one GitHub triage agent and the reviewed resources it needs. +``` + +## JSON Compatibility + +The package contract may point `openclaw.claw` at a JSON file containing the +grouped top-level object. JSON input passes through the same strict schema, +defaults, diagnostics, and lifecycle. `CLAW.md` and JSON are two serializations +of the same schema version, not different capability levels. + +## Compatibility and Evolution + +Schema evolution requires a new integer `schemaVersion`. Consumers must reject +unsupported versions rather than partially apply them. New optional fields must +not be added to version 1 because strict v1 consumers reject unknown fields. + +There is no canonical byte serialization. Producers should emit stable field +ordering and formatting for reviewable diffs, but semantic equality is based on +the parsed manifest. Artifact and source integrity remains byte-based. + +## Diagnostics + +Every rejection must identify a machine-readable code that remains stable for +the specification major version, the validation phase, and the most specific +manifest or package path available. Human messages must explain the violated +rule and a corrective action without including secret values or raw sensitive +owner errors. Consumers should return all independently actionable schema +findings from one read, but must stop before policy checks or mutation when +parsing or schema validation fails. + +Diagnostics are not an extension mechanism. A warning must not permit a +consumer to ignore an unknown field, unsupported component, unsafe path, or +missing required package source and still call the Claw valid. + +## Consumer Conformance + +A conforming consumer must: + +- parse the `CLAW.md` envelope and equivalent grouped JSON form as specified; +- reject duplicate YAML keys and unknown schema fields; +- validate all identifiers, exact versions, paths, environment references, + cron expressions, timezones, and uniqueness constraints; +- ignore the Markdown body for runtime behavior; +- preserve original bytes for integrity calculations; +- reject a `CLAW.md` file larger than 1 MiB before parsing, including when it + grows during the read; +- report unresolved environment and OAuth prerequisites without reading or + persisting their values; +- emit actionable diagnostics without exposing resolved secrets; +- reject an unsupported schema version before planning mutation. + +## Producer Conformance + +A conforming producer must: + +- emit UTF-8 `CLAW.md` with one YAML frontmatter block; +- emit only schema version 1 fields and exact dependency versions; +- keep all referenced workspace sources inside the enclosing package; +- use exact package and package-manager dependency versions and explicit cron + timezones; +- place human explanation, not executable declarations, in the Markdown body; +- exclude credentials and operator-owned runtime choices; +- validate the result against this specification before publication or export. diff --git a/rfcs/0016/claw-package-v1-spec.md b/rfcs/0016/claw-package-v1-spec.md new file mode 100644 index 00000000..c04dbdbc --- /dev/null +++ b/rfcs/0016/claw-package-v1-spec.md @@ -0,0 +1,555 @@ +# Claw Package v1 Specification + +This document is the implementer-facing package and lifecycle-boundary +specification for RFC 0016, Claws. It defines how one Claw manifest and its +referenced files are identified, validated, published, resolved, and handed to +an OpenClaw lifecycle implementation. + +Status: experimental draft, tied to RFC 0016. + +## Scope + +This specification defines: + +- package identity and required metadata; +- package layout and manifest selection; +- archive and filesystem safety requirements; +- publication and registry validation boundaries; +- artifact integrity and exact-version resolution; +- the contract between a registry and an applying harness; +- lifecycle ownership requirements for add, update, status, and remove. + +The grouped manifest schema and `CLAW.md` envelope are defined by +[`claw-md-v1-spec.md`](claw-md-v1-spec.md). Equivalent grouped JSON passes +through the same validator and lifecycle. + +This specification does not define: + +- a new package transport or dependency solver; +- a replacement for skill or plugin packages; +- credentials, local bindings, or host policy; +- the physical schema of OpenClaw provenance storage; +- a cross-harness command-line standard; +- whole-instance backup, restore, or migration. + +## Terminology + +- **Artifact**: the exact immutable package bytes identified by package name, + version, byte length, and digest. +- **Development snapshot**: one immutable local read of a development manifest + and every package file it references. +- **Owner**: the existing OpenClaw subsystem authoritative for an agent, file, + skill, plugin, MCP server, or scheduler record. +- **Managed resource**: a resource created specifically for one installed Claw + with an exclusive identity that the Claw lifecycle may reconcile and remove + after ownership and drift checks. +- **Referenced resource**: a shared canonical resource on which a Claw depends + without acquiring exclusive lifetime authority. +- **Dependency edge**: the current relationship between an installed Claw and + a referenced resource. It is warning and cleanup evidence, not an uninstall + lock or historical reference count. +- **Resource origin**: whether Claw add introduced a canonical resource or + declaration or found it already present. Origin informs cleanup eligibility + but is not ownership. +- **Applied**: every consented mutation completed or an existing canonical owner + was safely referenced. +- **Ready**: the applied agent also has all local credentials, executables, + bindings, and runtime prerequisites needed to operate as declared. +- **Application profile**: the owner mapping and lifecycle behavior required to + turn a manifest into a runnable agent on one harness. + +## Package Model + +A Claw package is a versioned, immutable distribution of one complete agent +definition. It contains: + +- package identity in `package.json`; +- one `CLAW.md` or equivalent grouped JSON manifest; +- every workspace source file referenced by that manifest. + +The package composes existing skills, plugins, MCP declarations, workspace +files, agent settings, and scheduled work. It is not a plugin, a plugin bundle, +or a replacement package type for those artifacts. Applying it delegates each +resource to its existing OpenClaw owner. + +One package adds one new agent. It must not adopt, merge into, replace, or +silently update an agent that the operator already owns. + +## Required Package Metadata + +The package root must contain a UTF-8 JSON `package.json` with: + +```json +{ + "name": "@acme/github-triage", + "version": "1.2.0", + "type": "module", + "openclaw": { + "claw": "CLAW.md" + } +} +``` + +| Field | Required | Semantics | +| --- | --- | --- | +| `name` | Yes | Canonical package coordinate assigned by the registry. Display slugs and aliases are not identity. | +| `version` | Yes | Exact canonical SemVer 2.0.0 version. Tags, ranges, and a leading `v` are forbidden. | +| `openclaw.claw` | Yes | Package-relative path to the manifest. | +| `type` | No | Ordinary package metadata; it does not affect Claw parsing. | + +Registry identity, version, and publisher ownership come from this package +metadata and the authenticated publish operation. They must not be duplicated +as authoritative fields inside the Claw manifest. + +At publication, the declared `name` and `version` must exactly match the +authenticated publish coordinate. A mismatch must reject the publication. +Registries must reject an identity that is not canonical under their published +package-name rules rather than silently normalizing it to a different package. + +## Package Layout + +An illustrative package is: + +```text +github-triage/ +|-- package.json +|-- CLAW.md +`-- workspace/ + |-- AGENTS.md + |-- SOUL.md + `-- reference/ + `-- triage-policy.md +``` + +All manifest paths and referenced workspace sources must resolve inside the +unpacked package root. A registry must verify that every declared source exists +in the uploaded artifact before accepting a version. + +## Portable Path Rules + +Package paths must be safe on supported OpenClaw filesystems. In addition to +the relative-path rules in the manifest specification, publishers and +registries must reject: + +- absolute POSIX, UNC, or drive-qualified paths; +- `.` or `..` traversal segments; +- NUL and control characters; +- Windows-reserved path components and invalid filename characters; +- components with trailing spaces or dots; +- two paths that collide after slash normalization, Unicode NFC normalization, + and case folding; +- a manifest path or workspace source whose canonical realpath escapes the + package root; +- symlinks, hardlinks, device files, sockets, and every other entry that is not + an ordinary directory or regular file. + +Consumers must apply bounded file-size and aggregate extraction limits. Limits +are implementation policy and should be documented by the registry or harness; +exceeding them must fail closed rather than truncate content. +Claws must not invent per-capability quotas such as a Claw-only scheduler count; +canonical owner limits apply uniformly. General package, manifest, extraction, +and plan-size limits may protect parsing and resource use across all fields. + +Archive entry names must also be unique under the portable collision key before +extraction. Consumers must not trust archive ordering to resolve duplicates. +Executable bits, owners, groups, timestamps, and other host metadata are not +portable package semantics and must not grant execution authority after +extraction. + +## Manifest Selection + +`openclaw.claw` selects the one manifest for the package. The path must resolve +to a regular UTF-8 text file inside the package. + +If the selected basename is `CLAW.md`, compared case-insensitively, the consumer +uses the Markdown-envelope parser. Other selected filenames are parsed as JSON. +Both forms pass through the same strict schema version 1 validator. + +A package must not select behavior from package scripts or another undeclared +manifest. Installing or inspecting a Claw package must not execute package +lifecycle scripts merely to discover its manifest. The `CLAW.md` body remains +documentation only. + +## Publication Validation Pipeline + +A conforming registry must validate a publication in this order: + +1. Authenticate the publisher and resolve the requested package coordinate. +2. Verify that `package.json` identity matches that coordinate exactly. +3. Safely enumerate and extract the artifact under package size and path limits. +4. Resolve `openclaw.claw` inside the package root. +5. Parse the selected `CLAW.md` or JSON document. +6. Validate the strict schema version 1 manifest. +7. Verify that every workspace source exists and is a safe regular file, and + that any local avatar resolves through a declared workspace destination. +8. Apply registry ownership, visibility, moderation, malware, and security + scanning rules. +9. Compute and retain the immutable artifact digest over the exact distributed + artifact bytes. +10. Store a bounded public safe summary derived from the validated manifest. + +The exact artifact remains the authoritative stored declaration. A registry is +not required to duplicate the parsed full manifest into its metadata store; if +it does, that copy must remain private and must fit the registry's documented +storage limits without truncation. + +Validation is all-or-nothing. A registry must not publish a partial package or +silently discard unsupported manifest fields or components. + +## Artifact Resolution and Integrity + +A feed or registry result used for add or update must resolve to an exact +package name, exact version, artifact location, and immutable artifact digest +formatted as `sha256:` followed by 64 lowercase hexadecimal characters. The +consumer records the observed byte length and must also verify it when the +registry supplies an expected length. +Floating tags and version ranges may be discovery inputs, but they must be +resolved before a managed lifecycle plan is produced. + +Artifact metadata must identify the archive format or transport kind. A +consumer must select its bounded safe extractor from that metadata and must not +assume that every registry artifact uses the same archive format. + +The registry artifact digest covers the exact distributed artifact bytes. The +trusted registry or signed feed binds that digest to package identity; the +digest alone proves byte equality, not publisher identity, review, or safety. + +A local development source must be materialized as one immutable planning +snapshot containing the exact manifest bytes and every referenced workspace +source path and byte sequence. Its development digest must cover that complete +snapshot plus the canonical source location. Hashing only the manifest is not +sufficient. Development and registry digests identify different trust layers +and must not be presented as interchangeable proofs. + +A consumer must verify the expected artifact digest before trusting package +contents. Validation and integrity do not imply that package code or declared +capabilities are approved; existing source policy, scanning, and install safety +checks still apply to every dependency. + +## Registry and Client Boundary + +A registry such as ClawHub owns: + +- authenticated publication and package ownership; +- immutable versions and artifact storage; +- package validation and security eligibility; +- safe search/detail summaries; +- exact artifact resolution and hosted feed entries. + +OpenClaw owns: + +- local package and manifest validation; +- read-only planning and operator consent; +- creation of the new agent and workspace; +- delegation to skill, plugin, MCP, agent, workspace, and scheduler owners; +- local provenance, status, diagnostics, update, export, and removal. + +Registry approval of a Claw must not transitively approve a skill or plugin +dependency. The client must resolve and evaluate every dependency through its +normal policy and installer path. + +During experimentation, a registry must not redefine an already published +stable plugin/skill feed schema by adding a Claw entry variant under the same +schema version. It may publish Claws through a separately identified, gated, +and versioned experimental feed contract. A disabled deployment must fail +closed before reading or serving stored Claw feed state, and an ungated edge +redirect must not expose the experimental route indirectly. + +Public search and release APIs should expose a bounded, derived summary for +indexing. Before consent, the applying client must make the exact grouped +manifest available for review and display its complete package effects from the +downloaded artifact under the artifact's visibility and authorization rules. +Valid packages cannot contain secrets. The downloaded artifact remains the +authoritative full declaration; a summary must not replace or contradict it. + +## Read-Only Planning and Consent + +Inspection validates package metadata and the manifest without reading or +mutating local lifecycle state. Add dry-run resolves the final local agent id, +workspace, dependencies, MCP servers, files, scheduled work, local credential +prerequisites, and every external executable or downloadable artifact. It +reports all actions, retained resources, conflicts, blockers, and post-add +readiness requirements. + +The plan must expose the security-relevant effect of each action: exact package +identity and integrity; workspace source, destination, and content digest; MCP +transport, executable and literal arguments or remote URL, environment variable +names, authentication mode, and tool filters; and cron schedule, timezone, +session, message, and delivery behavior. Secret values must remain undisclosed. +Any registry trust warning associated with a resolved package is part of that +effect and must remain visible in both machine-readable and human preview. + +Capability escalation is classified consistently across owners. Adding +executable package code, plugin or tool access, an MCP execution or network +surface, or recurring work requires a distinct machine-readable record and +human-readable disclosure rather than being hidden in ordinary content +reconciliation. The same classification applies during add and update; an +owner must not invent a weaker capability-specific approval. + +An application profile may satisfy capability and content consent with one +confirmation only when the plan represents the capability set separately and +the supplied integrity token binds both sets exactly. A profile may instead +require a separate capability prompt or aggregate capability records across +several plans before the first mutation. A changed capability record +invalidates prior consent in either model. + +The OpenClaw application profile marks each escalation record with +`requiresDistinctConsent: true`. This is a host-facing signal that the change +must receive distinct disclosure and explicit acknowledgment; it does not by +itself require a second portable CLI flag. OpenClaw's CLI acknowledgment is the +exact plan-integrity token entered after that separate disclosure. + +Mutation requires explicit consent after the complete plan is available. A +feature or deployment gate is not consent. A package must not cause mutation +merely by being discovered, downloaded, inspected, or passed through an +ordinary package installer. + +Consent must bind to the exact package or development snapshot digest, final +agent id, workspace, action set, and expected local owner state shown in the +plan. Immediately before mutation, the client must rebuild or revalidate those +inputs. Resolved dependency integrity, install identity, and trust warning are +included in that binding. A change to any consented digest, destination, package owner, owner +configuration value, scheduler record, or file-presence expectation invalidates +consent and requires a new plan; the client must not silently apply a materially +different plan. + +Agent-id or workspace collisions fail closed. An explicit override may choose +an unused id or workspace, but it must not adopt an existing agent or managed +workspace. + +## Ownership and Provenance + +After consent, the lifecycle delegates resources to their canonical owners and +records enough shared provenance to explain and reconcile the resulting agent. +At minimum, provenance must identify: + +- Claw package name, version, source, and integrity; +- final local agent id and workspace; +- the consented plan identity and applied manifest schema version; +- generated agent configuration digest and owned field paths; +- managed workspace paths and content digests; +- exact skill and plugin dependency edges, resource origin + (`claw-introduced` or `pre-existing`), and current non-Claw ownership; +- MCP names, managed or referenced relationship, resource origin, current + non-Claw ownership, and redacted configuration digests; +- manifest cron ids and scheduler record ids; +- per-owner pending, complete, partial, failed, and cleanup states; +- timestamps and actor or caller identity when the host can establish one. + +Credentials and resolved environment values must never be persisted in Claw +provenance. + +Provenance explains ownership and dependency relationships. It is not an +uninstall lock and does not replace canonical owner state. + +The managed or referenced relationship is derived during planning from the +resource kind and canonical owner state. A package author cannot declare +deletion authority. Agents, workspace files, agent-pinned scheduler jobs, and + new collision-free MCP declarations are managed. Shared package artifacts and + plugins are referenced even when add introduced them. A skill materialized + exclusively inside the new agent workspace is managed workspace state, while + a skill installation shared outside that workspace is referenced. An + identical pre-existing MCP declaration is referenced rather than adopted. + +Provenance stores current identities, integrity, dependency edges, and pending +or incomplete cleanup state. Implementations must not require a historical +operation ledger or stored reference-count history. Any cleanup decision uses +the current enumerated dependency edges and canonical owner state. + +Applied state and ready state are distinct. A complete add means every declared +mutation was applied or safely referenced. Status must separately report +unresolved environment placeholders, incomplete OAuth login, unavailable MCP +executables, disabled or missing scheduler dependencies, and other local +prerequisites that prevent the agent from operating as declared. + +## Add Semantics + +A conforming add implementation must: + +- create exactly one new agent and one new workspace; +- fail the complete add when any declared component is unsupported, blocked, + invalid, or unavailable; +- use existing skill and plugin installers and safety checks; +- write only confined workspace files; +- map MCP declarations to the existing MCP owner; +- create scheduler records pinned to the final local agent id; +- persist pending owner provenance before each external mutation; +- record successful external mutations as they occur; +- report a partial result when owners cannot share one atomic transaction. + +On failure, add must stop later owners and compensate only work whose canonical +owner can prove a safe inverse. Completed or uncertain external mutations remain +in resumable provenance with a partial root status. A retry, doctor, or remove +uses that current state; add must not report a partially created agent as +successfully added. + +## Update Semantics + +Update targets the installed agent identified by provenance and never another +agent that happens to share a manifest id. It must produce a read-only +reconciliation plan before separately consented mutation. + +The installed local agent id and workspace are immutable update identity. A +different `agent.id` in a later package version changes the default for new adds +only; it must not rename or move an existing installed agent. Update may move to +an older or newer exact package version only when that target is explicit in the +consented plan. There is no implicit background update authority in v1. + +At the mutation boundary, each owner must revalidate the strongest available +expected state, including file presence and digest, package ownership, MCP +configuration, scheduler identity, and agent/root provenance. Local edits or +concurrent changes become conflicts rather than silent overwrites. + +An update plan must classify each resource as create, change, remove, retain, +requires-local-configuration, or conflict. It must preserve unrelated owner +state and must not replace a global plugin while another installed Claw or a +direct owner requires a different version. + +Removing a package declaration during update releases that Claw's reference. +It does not imply artifact uninstall during the update transaction. Irreversible +or uncertain owner outcomes must be retained in current provenance and reported +as `status: partial`, including in structured CLI output. + +Before changing or removing a scheduler record, update and remove must read the +live record through the scheduler owner and compare its owned definition with +provenance. Operator-modified jobs are conflicts and must not be overwritten or +deleted. + +## Resource Limits + +A consumer must reject a Claw manifest larger than 1 MiB and package metadata +larger than 256 KiB before parsing. Reads must remain bounded if a file grows +after an initial metadata check. Existing canonical extraction, workspace-file, +aggregate-workspace, and plan-output limits continue to apply. + +## Remove Semantics + +Remove must first produce a plan and then require explicit consent. It must +delegate agent, skill, plugin, MCP, workspace, and scheduler cleanup to their +canonical owner lifecycles. + +Remove must disable Claw-owned recurring work before deleting the agent or its +workspace content. If recurring work cannot be proven disabled, cleanup is +partial and the failure remains visible; remove must not claim success merely +because later local records were deleted. + +Managed resources are selected for cleanup by default. Referenced resources are +retained by default while the removing Claw's dependency edges are released. +The plan must show the relationship, origin, expected integrity, every other +known Claw dependency edge, known non-Claw ownership, and the canonical cleanup +owner for each resource. + +The operator must be offered these referenced-resource dispositions: + +- **retain**: release only this Claw's dependency edge. This is the default. +- **remove-if-unused**: invoke canonical removal only when the resource has no + other Claw dependency edge or known non-Claw owner, was introduced by Claw + add, is complete, unchanged, and unambiguous, and its canonical owner permits + removal. +- **remove-selected**: invoke canonical removal for specifically selected + resources after showing all known affected Claws and non-Claw owners. A + remaining dependency or pre-existing origin requires stronger explicit + confirmation but is not a hidden uninstall lock. + +The chosen disposition and affected resource identities must be part of the +integrity-bound remove plan. Non-interactive mutation must identify its cleanup +mode explicitly; it must not broaden default `retain` behavior merely because a +general `--yes` flag is present. Referenced cleanup runs after managed-resource +cleanup so failure cannot damage a still-live Claw agent. + +If an operator explicitly uninstalls an artifact despite a Claw-reference +warning, canonical uninstall semantics win. The Claw becomes degraded and +status must report the missing dependency. Claw status or remove must not +silently reinstall it. + +Resource origin must remain current cleanup evidence while Claw dependency +edges remain. `remove-if-unused` eligibility is evaluated from resource origin, +current dependency edges, and canonical owner state, not from which Claw happens +to be removed last. Removal order must not change the result. + +Conversely, a later direct install or explicit operator adoption must add +independent ownership through the shared package lifecycle. Once independently +owned, the artifact is retained when no Claw dependency edge remains. A +Claw lifecycle must not infer that an idempotent direct install conveys no +ownership merely because the exact artifact was already present. + +The same dispositions apply to referenced MCP declarations. A newly created +Claw-managed MCP declaration is removed by default when unchanged; an identical +pre-existing MCP declaration is referenced and retained by default. Remove must +preserve locally modified files, unrelated MCP declarations, channel bindings, +credentials, operator settings, and any resource whose ownership or expected +state cannot be proven. Failed cleanup remains visible to status and +diagnostics. + +## Development Sources and Export + +A local unpackaged manifest may be inspected and, when explicitly supported, +added under a synthesized development identity. The consumer must record its +canonical source path and exact digest. A development identity must not be +mistaken for an authenticated registry identity. + +An unpacked development directory may select its manifest through a symlink +whose canonical target is a regular file inside that directory. This authoring +convenience is not publishable package content: registry artifacts continue to +reject links, and referenced workspace sources remain regular, non-linked +files. + +Export creates a new package directory and must fail if the output directory +already exists. It emits `package.json`, `CLAW.md`, and confined +workspace sources. Export includes only portable supported state and excludes +secrets, resolved environment values, models, providers, bindings, sessions, +logs, caches, and unrelated global configuration. + +Export may preserve an original package name and version only by returning the +byte-for-byte original artifact with the same digest. Any regenerated package, +including one exported from an unchanged installation, must use a new +development-safe or derivative identity and version so it does not impersonate +the publisher's immutable artifact. Publication under another publisher's +namespace remains forbidden regardless of local provenance. + +## Compatibility and Evolution + +Package v1 is identified by a manifest with `schemaVersion: 1` and the metadata +contract above. Registry transport may evolve independently as long as it still +delivers the exact identity, version, digest, and package bytes. + +Package and manifest v1 define the OpenClaw application profile. A different +harness may inspect the portable data or implement that complete profile, and a +future specification may define additional harness profiles. A consumer must +not claim v1 application conformance if it drops, translates approximately, or +cannot own a declared component. It may inspect such a package, but add must +fail the complete plan rather than silently degrade the Claw. + +## Registry Conformance + +A conforming registry must: + +- authenticate publication and bind it to exact package identity; +- enforce package containment and portable path collision rules; +- parse and validate the selected manifest strictly; +- verify every referenced source file; +- retain exact artifact length and SHA-256 integrity; +- retain a bounded public summary derived from the validated artifact without + requiring a second full-manifest copy in registry metadata; +- allow authorized clients to retrieve the exact artifact for local manifest + review; +- never imply that Claw approval bypasses dependency policy. + +## Client Conformance + +A conforming applying client must: + +- verify package identity, containment, manifest schema, and integrity locally; +- resolve exact dependencies before planning; +- expose a complete read-only plan and require explicit consent; +- bind mutation to the consented artifact, destinations, actions, and expected + owner state; +- preserve the one-package-one-new-agent invariant; +- delegate resources to canonical owners and record provenance; +- fail closed on collisions, unsupported components, and unsafe paths; +- distinguish applied state from local operational readiness; +- preserve drifted or independently owned state during update and remove; +- derive managed and referenced relationships from canonical owner state; +- retain referenced resources by default and bind any operator-selected + referenced cleanup into the exact remove plan; +- report partial outcomes and leave them diagnosable.