Skip to content

docs: add MCP, subagents, skills, voice, and hardware documentation - #776

Closed
telagod wants to merge 1 commit into
nullclaw:mainfrom
telagod:docs/add-feature-docs
Closed

telagod wants to merge 1 commit into
nullclaw:mainfrom
telagod:docs/add-feature-docs

Conversation

@telagod

@telagod telagod commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Problem

Five subsystems have substantial code implementations but no user-facing documentation:

Subsystem Source Lines Previous docs
MCP src/mcp.zig 915 Config example in README only
Subagents src/subagent.zig + src/subagent_runner.zig 868+ Brief mention in configuration.md
Skills src/skillforge.zig 974 None
Voice src/voice.zig 603 None
Hardware src/hardware.zig + src/peripherals.zig substantial README architecture table only

Changes

New English docs (docs/en/)

  • mcp.md (94 lines) — transports, config fields, tool discovery, security, tool filtering
  • subagents.md (73 lines) — spawning, workspace isolation, result routing, query API
  • skills.md (80 lines) — CLI commands, manifest formats, SkillForge auto-discovery scoring
  • voice.md (57 lines) — Whisper config, supported providers, transcription pipeline
  • hardware.md (101 lines) — board discovery, peripheral drivers, agent tools, security

Chinese stubs (docs/zh/)

  • mcp.md, subagents.md, skills.md, voice.md, hardware.md — translated structure with key terms, ready for full translation

Navigation updates

  • docs/README.md — 5 new topical doc links
  • docs/en/README.md — added to navigation
  • docs/zh/README.md — added to navigation

Files

13 files changed, +651 lines

New feature documentation for 5 subsystems that had substantial code
implementations but no user-facing docs:

English (docs/en/):
- mcp.md — MCP transports, config, tool discovery, security, filtering
- subagents.md — spawning, workspace isolation, result routing
- skills.md — CLI commands, manifest formats, SkillForge auto-discovery
- voice.md — Whisper integration, providers, channel integration
- hardware.md — board discovery, peripheral drivers, agent tools

Chinese stubs (docs/zh/):
- mcp.md, subagents.md, skills.md, voice.md, hardware.md

Navigation updated:
- docs/README.md — added 5 new topical doc links
- docs/en/README.md — added to navigation section
- docs/zh/README.md — added to navigation section
vernonstinebaker pushed a commit to vernonstinebaker/nullclaw that referenced this pull request Sep 23, 2026
Rank-assessed the 19 open third-party PRs on nullclaw/nullclaw against our
environments (webdav via MCP, docs/en+zh, three-host fleet). Ledger order:
nullclaw#985, nullclaw#776, nullclaw#979, nullclaw#777, nullclaw#984, plus a core-review status update. nullclaw#969/nullclaw#980
and tier-3/4 PRs recorded as deferred/rejected with reasons. Handoff updated:
hardening landed as 90e4b01.
vernonstinebaker pushed a commit to vernonstinebaker/nullclaw that referenced this pull request Sep 23, 2026
Applied from nullclaw#776 (telagod), en+zh. Ten new pages applied
verbatim; README index hunks ported manually because our READMEs diverged.

Intake-time corrections, verified against this tree:
- mcp.md env/headers config fields are string->string objects
  (src/config_parse.zig parses objects only), not {key,value} arrays.
- subagents.md: subagent limits (15 iterations / 4 concurrent) are built-in
  defaults (src/subagent.zig:52), not agents.defaults.* config keys; the JSON
  block documenting nonexistent keys was replaced with a limits table.
- mcp.md tool filtering (en+zh): documented the automatic lexical narrowing
  that applies ONLY when no tool_filter_groups are configured, and that any
  explicit group makes configured groups authoritative.

All internal doc links verified. Full suite 7535 passed / 9 skipped, exit 0.
Tracked as U-2 in PLAN.md; new U-7 records README merge-prefix damage found
during intake (fixed separately).
vernonstinebaker pushed a commit to vernonstinebaker/nullclaw that referenced this pull request Sep 23, 2026
…, nullclaw#777

User decision 2026-09-23: U-3 (nullclaw#979) and U-5 (nullclaw#984) deferred, one PR at a
time with check-ins, docs must be verified accurate for this tree, and all
changes follow AGENTS.md / CONTRIBUTING.md.
@vernonstinebaker

Copy link
Copy Markdown
Contributor

Merged into the vernonstinebaker/nullclaw fork at 29c02d55. Two corrections applied during intake that may help if this lands upstream: (1) mcp_servers.<id>.env/.headers are parsed as string→string objects in the current parser, not {key,value} arrays — the doc table now says objects; (2) subagent limits (15 iterations / 4 concurrent) are built-in defaults in src/subagent.zig, not agents.defaults.subagent_max_* keys, so we replaced that JSON block with a limits table. We also documented that automatic MCP narrowing only applies when no tool_filter_groups are configured.

vernonstinebaker pushed a commit to vernonstinebaker/nullclaw that referenced this pull request Sep 23, 2026
Commit 575a616 (beginner's guide) landed with two-letter-colon prefixes on
45 lines across docs/README.md, docs/en/README.md, and docs/zh/README.md
(e.g. 'MB:## Core User Docs', 'QV:- [Beginner's Guide]…'), breaking heading
and list rendering on the public docs landing pages and causing the nullclaw#776
README hunks to conflict during intake.

Restoration is mechanical prefix removal, verified against the parent of the
introducing commit: stripped blocks match 575a616^ exactly where the content
pre-existed, and the beginner-guide additions survive the strip intact. The
resulting double-blank pairs were collapsed. All links resolve; suite 7535
passed / 9 skipped. Tracked as U-7 in PLAN.md.
vernonstinebaker pushed a commit to vernonstinebaker/nullclaw that referenced this pull request Sep 24, 2026
Incremental PR-by-PR plan for exercising the new committer access: wave 0
pre-flight, wave 1 docs (ours first; nullclaw#776 needs three verified corrections,
nullclaw#777 must not merge with its 0.15.2 pin), wave 2 our code PRs smallest-first,
wave 3 nullclaw#987 then un-drafted nullclaw#971. Per-code-PR loop: merge, fork sync, suite,
4-target build, 4-host deploy, two-turn smoke. Docker/OrbStack recorded as
wave-4 decision (upstream nullclaw#449 still open; images publish via nullbuilder).
Docs-only merges flagged to skip rebuild (binary cannot change) — pending
user confirmation.

@vernonstinebaker vernonstinebaker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@telagod Three corrections before this can be merged. They are checked against current main, and the suggestions below are the text to apply. Committing them keeps the PR yours.

  1. mcp_servers.<id>.env and .headers are string-to-string objects. The parser does not accept [{"key","value"}] arrays.
  2. The subagent limits (15 iterations, 4 concurrent) are built-in defaults in src/subagent.zig. agents.defaults.subagent_max_iterations and subagent_max_concurrent are not config keys.
  3. With no tool_filter_groups, the agent lexically narrows MCP tools (name tokens of 5+ characters, at most 16). Any explicit group disables that and makes the groups authoritative.

English and Chinese pages both need the limit and filtering corrections. Please use Add suggestion to batch, then Commit suggestions. I will stay off the branch.

Comment thread docs/en/mcp.md
Comment on lines +41 to +44
| `env` | array | `[]` | Environment variables: `[{"key": "K", "value": "V"}]` |
| `url` | string | — | HTTP endpoint URL (required for http transport) |
| `timeout_ms` | number | `10000` | Per-request timeout in milliseconds |
| `headers` | array | `[]` | Custom HTTP headers: `[{"key": "K", "value": "V"}]` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env and headers are objects, matching the JSON example above this table. The parser stores them as string-to-string maps.

Suggested change
| `env` | array | `[]` | Environment variables: `[{"key": "K", "value": "V"}]` |
| `url` | string | — | HTTP endpoint URL (required for http transport) |
| `timeout_ms` | number | `10000` | Per-request timeout in milliseconds |
| `headers` | array | `[]` | Custom HTTP headers: `[{"key": "K", "value": "V"}]` |
| `env` | object | `{}` | Environment overrides: string → string map (`{"KEY": "value"}`) |
| `url` | string | — | HTTP endpoint URL (required for http transport) |
| `timeout_ms` | number | `10000` | Per-request timeout in milliseconds |
| `headers` | object | `{}` | Custom HTTP headers: string → string map |

Comment thread docs/en/mcp.md
Comment on lines +87 to +88
- `always`: Tools matching the pattern are always included.
- `dynamic`: Tools are included only when the user message contains a keyword.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the default path. narrowMcpToolsForTurn runs only when tool_filter_groups is empty (src/agent/root.zig). Any configured group turns that heuristic off.

Suggested change
- `always`: Tools matching the pattern are always included.
- `dynamic`: Tools are included only when the user message contains a keyword.
- `always`: Tools matching the pattern are always included.
- `dynamic`: Tools are included only when the user message contains a keyword.
When **no** `tool_filter_groups` are configured, the agent applies an automatic
lexical narrowing pass instead: MCP tools whose name tokens (5+ characters)
match the current user message are kept, up to 16 tools. Configuring any
explicit group — even a single `always` group — disables this heuristic and
makes your groups authoritative, which is the recommended way to guarantee an
always-on MCP tool (for example `mcp_webdav_*`) stays available on short
follow-ups such as `continue`.

Comment thread docs/en/subagents.md
Comment on lines +19 to +37
## Configuration

Subagent limits are controlled in `~/.nullclaw/config.json`:

```json
{
"agents": {
"defaults": {
"subagent_max_iterations": 15,
"subagent_max_concurrent": 4
}
}
}
```

| Field | Default | Notes |
|-------|---------|-------|
| `subagent_max_iterations` | 15 | Max tool loop iterations per subagent |
| `subagent_max_concurrent` | 4 | Max concurrent subagents |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These keys are not read from config. SubagentConfig defaults are max_iterations = 15 and max_concurrent = 4 in src/subagent.zig.

Suggested change
## Configuration
Subagent limits are controlled in `~/.nullclaw/config.json`:
```json
{
"agents": {
"defaults": {
"subagent_max_iterations": 15,
"subagent_max_concurrent": 4
}
}
}
```
| Field | Default | Notes |
|-------|---------|-------|
| `subagent_max_iterations` | 15 | Max tool loop iterations per subagent |
| `subagent_max_concurrent` | 4 | Max concurrent subagents |
## Limits
Subagent limits are built in and not currently configurable via `config.json`:
| Limit | Default | Notes |
|-------|---------|-------|
| Max tool loop iterations | 15 | Per subagent |
| Max concurrent subagents | 4 | Across the manager |

Comment thread docs/zh/mcp.md
- Header 值禁止换行符
- 单个服务器连接失败不影响其他工具

## 相关页面

@vernonstinebaker vernonstinebaker Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The English page documents tool filtering. The Chinese page should describe the same behavior, including the automatic narrowing that applies only when no groups are configured.

Suggested change
## 相关页面
## 工具过滤
通过 `agent.tool_filter_groups` 控制每轮包含哪些 MCP 工具:
~~~json
{
"agent": {
"tool_filter_groups": [
{
"mode": "always",
"tools": ["mcp_filesystem_*"]
},
{
"mode": "dynamic",
"tools": ["mcp_jira_*"],
"keywords": ["ticket", "jira", "issue"]
}
]
}
}
~~~
- `always`:匹配该模式的工具始终包含。
- `dynamic`:仅当用户消息包含关键词时才包含。
若**未配置**任何 `tool_filter_groups`,agent 会改用一次自动词法收窄:仅保留名称词元(5 个字符以上)与当前用户消息匹配的 MCP 工具,最多 16 个。只要配置了任一显式分组(哪怕只有一个 `always` 分组),该启发式即被禁用,分组配置完全生效——这是保证常驻 MCP 工具(例如 `mcp_webdav_*`)在 `continue` 之类的简短追问中仍然可用的推荐做法。
## 相关页面

Comment thread docs/zh/subagents.md
Comment on lines +17 to +28
## 配置

```json
{
"agents": {
"defaults": {
"subagent_max_iterations": 15,
"subagent_max_concurrent": 4
}
}
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

与英文页相同:这两个字段不是配置项,15 和 4 是 src/subagent.zig 里的内置默认值。

Suggested change
## 配置
```json
{
"agents": {
"defaults": {
"subagent_max_iterations": 15,
"subagent_max_concurrent": 4
}
}
}
```
## 限制
子 agent 的限制为内置值,目前无法通过 `config.json` 配置:
- 每个子 agent 最多 15 次工具循环迭代
- 最多 4 个并发子 agent

@vernonstinebaker

Copy link
Copy Markdown
Contributor

This applies cleanly, and it still needs an update before merge. The five suggestions on the review cover factual mismatches with current src/ (env/headers are string-to-string maps, subagent limits 15 and 4 are built in, and MCP narrowing runs only when no tool_filter_groups are set).

Please apply those suggestions and re-read the five pages against current main. They were written in April, and the MCP and subagent behavior has moved since then.

@vernonstinebaker

Copy link
Copy Markdown
Contributor

Closing as superseded by #1008, which was opened specifically to carry this work forward. Credit to @telagod — this is the PR that added the MCP, subagents, skills, voice, and hardware pages, and #1008 would not exist without it.

#1008 re-adds the same page set with corrections, rather than merging this branch:

  • Keeps the Zig 0.16.0 pin (this branch is written against an older pin).
  • Matches the MCP page to actual tool_filter_groups behavior in the parser and agent, instead of describing a lexical narrowing pass that is not implemented.
  • The skills page is deliberately left to feat(skills): follow symlinked skill directories #1003, so it is not duplicated here.

The pages do already exist on main; #1008 replaces them with corrected versions. Its accuracy pass, pushed as 976d7467, also fixes things worth calling out because they were live inaccuracies in the shipped pages rather than just version drift:

  • nullclaw hardware flash and nullclaw hardware monitor are placeholders in runHardware — they only print a message, and monitor does not invoke udevadm. The page presented both as working commands and described real-time hotplug monitoring that does not exist.
  • The agent tool is hardware_board_info, not hardware_info.
  • spi was listed as an available tool; allTools never registers it.
  • delegate was described as spawning background subagents. It calls completeAgentPrompt synchronously and creates no task.
  • dynamic MCP filter groups were described as applying uniformly; they only take effect on the native tool-schema path, never in the text prompt.

English and Chinese pages are updated together in that PR, per AGENTS.md §7.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants