docs: an Example Plugins page, both languages
The wiki had no catalogue of the example plugins — grepping every page
for `wasm-plugin` returned nothing at all. There are now five of them
across three WIT worlds with five different grant sets, and the only way
to learn what any one did was to open its source.
Adds Example-Plugins / Example-Plugins-zh: what each plugin is for, its
tools, commands and event subscriptions, the grants it needs mapped to
the host imports it actually calls, its world, and its make target. Plus
which one to start from, since "the skeleton to copy" and "the one you
would install" are different plugins and the names do not say so.
Every cell was read out of the sources at nanopi `8dd8ae9` rather than
remembered, which caught two things worth stating on the page:
- `wasm-plugin-minimal` does NOT need `allow_fs`, though its source
declares `host-fs-read` — the declaration is behind
`#[allow(dead_code)]`, LTO drops the unused import, and it is absent
from the built world. The page says to check the component with
`wasm-tools component wit` rather than trust the source, because the
source can over-declare.
- `host-notify` needs no grant at all; it is bounded by a rate limit
rather than a gate, and the host owns the attribution prefix.
Also states plainly that shell hooks are the other half rather than the
lesser option — veto and never-missing-an-event are things only a hook
can do, and plugin event delivery is drop-on-busy — so readers do not
reach for a plugin to build an audit log.
The -zh half additionally covers building behind a restricted network
(cargo mirror, and checking `wasm32-wasip1` in the sysroot rather than
trusting `rustup target list`), following this wiki's split: the Chinese
pages carry that, the English ones never mention it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dev
committed
Sep 9, 2026
74d1e20
docs(debugging): the probe driver now matches the twelve-argument load
`PluginEngine::load(&path, allowlist, cwd, allow_fs, allow_net)` has
not compiled since v0.12: it takes twelve arguments, one per gate, plus
a store root, the plugin's identity (the `.wasm` stem, as the host
derives it) and the events grant. A driver that does not compile is
worse than no driver, since the reader assumes their plugin is at fault.
Gates move into a struct: ten arguments, four of them bool, is one
transposition away from testing a gate you did not mean to open.
Adds a `deliver_event` probe, and the three ways a probe differs from a
session: the store root points at a temp dir so it cannot clobber the
real store, host-notify goes straight to stderr with no drain loop, and
host-call-tool / host-send-user-message refuse regardless of the grant
because both are wired up by an agent the probe does not have.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
2526916
docs(plugin-dev): all nine imports, three worlds, and why the ladder needs stubs
The world snippet listed three imports and one world, and the page then
told the reader outright that plugins receive no lifecycle events. Both
were true in v0.11 and neither is now.
Adds the six remaining imports (with the two-string flattening the
template did not need before), the linear ladder, and the consequence
that trips people at build time: WIT cannot express an optional export,
so `--world extension-events` means shipping `list-commands` /
`execute-command` stubs. The host resolves those optionally — it is the
guest-side `component new` that refuses.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
a589145
docs: use the real unsatisfied-event notice, and the true try_lock site
Two paraphrases replaced with what the code actually emits: the
startup notice is src/wasm/mod.rs:400, not the doc comment's
"requested but refused", and the try_lock-and-drop delivery lives in
loader.rs rather than subscriber.rs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
92b08d9
docs(zh): add 插件事件订阅, the -zh half of Plugin-Events
_Sidebar.md has linked to this page since the v0.12 nav landed and
it did not exist. Covers the extension-events world: the
granted-intersect-requested double agreement computed once at
load, observe-only as a structural property rather than a policy,
try_lock-and-drop delivery, the 2s event epoch vs 30s for tool
calls, MAX_EVENTS_PER_PLUGIN, and the load-failure modes.
Verbatim strings taken from the code at 3a762b1: the "requested
event ... did not grant it" startup report, the dropped-delivery
line, the per-delta message for message_update and
tool_execution_update, and the events+allow_network exfiltration
warning.
message_end is documented as carrying turn_count and
response_length and NOT the assistant text, which is what
loop_.rs builds at this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
5846b9a
docs(zh): bring 能力门 up to v0.12
The -zh capabilities page still described v0.11: allow_fs and
allow_network only. Adds the four grants v0.12 shipped
(allow_store, allow_context, allow_tools, allow_send_message),
the two ungated output imports, and the /tools grant row.
Every bound, default and error string re-read out of the code at
3a762b1 rather than translated from the English page: the store
caps and their verbatim refusals, MAX_CONTEXT_BYTES and the
"previous contribution is unchanged" tail, the seven built-ins
allow_tools accepts, the three loop-guard strings and the cap of
20, MAX_NOTIFY_PER_TURN and the truncation return.
Two places where the Chinese page carries more than the English
one, per the asymmetric bilingual convention: a note that
host-http-get inherits the host process proxy so a proxy must NOT
go in url_allowlist, and that 4 KiB of context is ~1300 Chinese
characters because the bound is bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
60134dc
docs(home): the contract is nine imports and six exports, over three worlds
"Two exports and three imports" was the v0.11 shape. v0.12 added six
imports and two exports, so the one-screen summary understated what an
installed plugin can be granted — on the page most readers see first.
The linear ladder goes here too, with the reason it is a ladder: WIT
cannot express an optional export, so an events-only plugin still ships
command stubs. Imports, by contrast, need no new world, which is why the
older binaries keep loading.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
4a6e563
docs(features): v0.12 — one event vocabulary, nine imports, seven gates
The hooks table still listed pre_tool_use / post_tool_use /
user_prompt_submit as a "Claude Code parity" family. Those keys are now
a hard config error, so a reader following this page wrote a config that
refuses to start — the worst outcome the rename was chosen to avoid.
Also: the capability paragraph named only allow_fs and allow_network
(there are nine host imports behind seven grants now), the plugin blurb
still said plugins receive no lifecycle events, /tools and /quit were
missing from the slash-command list, and the version table had no
v0.12.0 row. The README-version note was stale in both directions:
that table now stops at v0.11.0, and VERSION is only bumped at the
release tag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
ad76d36
docs(zh): document v0.12's five new [[extensions]] grants
Configuration-zh listed only allow_fs / allow_network / url_allowlist.
Added allow_store, allow_context, allow_tools, allow_send_message and
events, with the defaults table and the note that every default is the
closed position — including that [] denies rather than allows.
allow_tools gets its own paragraph: it is a per-tool list, not a
boolean, because ["bash"] is arbitrary execution that walks past every
other grant.
Also documented deny_unknown_fields on [[extensions]] — a misspelled
grant is now a config load error — and the deliberate asymmetry with
unknown names inside `events`, which stay a plugin-load warning so the
stock non-wasm binary can keep ignoring the section.
Restricted-network note added for host-http-get: it inherits the
process proxy, but has a 10s timeout and does not follow redirects,
and url_allowlist matches the target host, not the proxy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
beb1bc4
docs(zh): bring Hooks-zh up to v0.12's event vocabulary
The page still told Chinese readers to write [[hooks.pre_tool_use]],
[[hooks.post_tool_use]], [[hooks.user_prompt_submit]] and
[[hooks.session_end]]. Those four keys were retired in v0.12 and
HooksSection carries deny_unknown_fields, so following this page
produced a config that fails to load outright.
Renamed all four on every surface the page mentions (config key,
payload `event`, NANOPI_EVENT, examples, prose), and added the
retired-key warning box plus the error-message section explaining
why it is a hard error and not a warning.
Also brought over from the EN rewrite: plugins now observe the same
eleven events (link to Plugin-Events-zh), the advisory-block report
line, the `input` refusal wording, tool_call_id being populated,
NANOPI_TOOL_CALL_ID, the session payload's new `reason` field, and
--no-hooks now cutting plugin event delivery too. Noted explicitly
that message_end carries only turn_count/response_length.
The restricted-network section keeps its Chinese-only advice and
gains the /new//resume//fork//import caveat on session_shutdown.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
b4d90a5
docs: new page for WASM lifecycle event subscriptions (EN)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
1d4b616
docs: store, context, tools, send-message, and the ungated pair (EN)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
0effa82
docs: the four new plugin grant keys and deny_unknown_fields (EN)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
8d25bee
docs: lifecycle hooks reference for v0.12 renames (EN)
The four retired Claude Code keys (pre_tool_use, post_tool_use,
user_prompt_submit, session_end) are now hard config errors, so the old
page told readers to write a config that will not load. Rewrites the
event table around PI's names, adds the exact rewrite error, the real
block markers, the session-payload `reason`, and NANOPI_TOOL_CALL_ID.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dev
committed
Sep 7, 2026
eed9c63
docs: lifecycle hooks reference (EN + zh)
Full reference for the eleven hook events in v0.11.0: trigger points,
which can block or transform, the stdin/stdout wire protocol, matcher
semantics per event, timeout-as-block, the four cumulative config
files, and --no-hooks. Two runnable examples (PreToolUse guard,
PostToolUse redaction).
States explicitly that hooks and WASM plugins are separate mechanisms
and that plugins receive no hook events; cross-links added on
Plugin-Development and Configuration in both languages.
830979b
docs: feature overview page (EN + zh)
A map of what nanopi actually implements, by area: model access,
sessions, built-in tools, TUI interaction, the four extensibility
mechanisms, the trust model, and version history back to v0.1.
Compiled from the source tree and git history rather than from the
README, which turned out to be partly stale — its version table still
lists v0.10.0 as current while Cargo.toml and VERSION are on 0.11.0.
The page notes that and points at VERSION as authoritative.
Structured to complement the README rather than duplicate it: install
steps and the flag table stay there, this page covers the shape of the
system and links out for detail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6cbfe36
docs: bilingual plugin & configuration wiki (v0.11.0)
Ten pages, English and Chinese, covering what the repo does not:
writing a WASM plugin end to end, the capability gates, debugging a
plugin without an LLM, and the two-layer config with its three merge
behaviours.
Content is from an actual walkthrough on Linux + wasmtime 19 — the
template compiles, the build commands ran, and the gate outputs are
pasted from real runs rather than inferred from the source.
Things that cost time to discover and are now written down:
- import returning a string takes a TRAILING ret_area out-param, while
an export returns a pointer to the (ptr,len) pair. Getting it
backwards fails at `wasm-tools component new`, not at runtime.
- `~` in extensions.path expands to $HOME and ignores NANOPI_HOME.
- extensions and hooks CONCATENATE across config layers; only scalars
override. You cannot disable a global plugin from a project config.
- the repo ships its own .nanopi/config.toml, which overrides global
settings when you test from the repo root.
- only imports you actually call survive LTO into the component world.
Chinese pages additionally cover working behind a restricted network
(crates.io index timeouts, --offline, mirror config, installing
wasm32-wasip1 when rustup can't). The English pages deliberately omit
all of it and use the standard commands.
Every page states the version it was verified against and how to
re-verify, since a wiki has no PR review to keep it honest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
47e1c5b