Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/command-inventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,7 @@
"--allowed-host",
"--host",
"--port",
"--timeout",
"--transport"
],
"subcommands": [
Expand Down
25 changes: 24 additions & 1 deletion .github/command-registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -14208,7 +14208,13 @@
"runnable": true,
"args": [
{
"name": "source target",
"name": "source",
"required": false,
"variadic": false,
"secret": false
},
{
"name": "target",
"required": false,
"variadic": false,
"secret": false
Expand Down Expand Up @@ -18317,6 +18323,23 @@
"cli_only": false,
"secret": false
},
{
"name": "timeout",
"shorthand": null,
"type": "duration",
"default": "5m0s",
"usage": "Longest one tool call may run before its command is stopped, such as 15m",
"hidden": false,
"deprecated": null,
"required": false,
"persistent": false,
"env": null,
"side_effect": null,
"json": null,
"output": null,
"cli_only": false,
"secret": false
},
{
"name": "transport",
"shorthand": "t",
Expand Down
1 change: 1 addition & 0 deletions .github/coverage-floors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal/backup 15 # measured 17.1 2026-10-05
internal/backup/destinations 40 # measured 42.1 2026-10-05
internal/backup/pitr 25 # measured 27.6 2026-10-05
internal/build 71 # measured 73.5 2026-10-05
internal/build/trustplan 74 # measured 76.2 2026-10-30
internal/builtin/admin 12 # measured 12.4 2026-10-08 (P7-CANON-19, moved from cmd/commands)
internal/bundle 64 # measured 67.0 2026-10-05
internal/bundle/appready 85 # measured 92.1 2026-10-10 (P7-PLUG-19)
Expand Down
4 changes: 2 additions & 2 deletions .github/facts.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
},
"schema_version": "1",
"sources": {
"openapi_sha256": "1f47f7be7d98810ce4eca08fb61bd930cc662290040b162bfc96fe6e602a6059",
"registry_sha256": "37fe98fe4dfa26f0c8af15f5cc50e9a5b81f499976850ae2b6066c536e8fe6c9"
"openapi_sha256": "11122bde68b446a20556664dbfe3d99d3b2b73b1af41fb1034c5ac3575c987a8",
"registry_sha256": "3846753c456f348e5ef3f1c74af81f7894244006b435268cc716663dc9266314"
},
"verbs": [
"init",
Expand Down
8 changes: 6 additions & 2 deletions .github/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -41231,11 +41231,15 @@
"properties": {
"args": {
"items": false,
"maxItems": 1,
"maxItems": 2,
"minItems": 0,
"prefixItems": [
{
"description": "source target",
"description": "source",
"type": "string"
},
{
"description": "target",
"type": "string"
}
],
Expand Down
2 changes: 1 addition & 1 deletion .github/wiki/Guide-Agents-MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ nself mcp setup --client claude-code --write # doc-check: skip registered in cmd

## One server per project

Run one MCP server per project. `nself mcp` must start inside a directory that holds an nSelf project, and its tools act on that project only. Do not point one server at several projects. If you work on two projects, register two servers, each started from its own project directory. Tool results then never mix up which stack was changed.
Run one MCP server per project. Start `nself mcp` in the project's directory; its tools act on that project only. Started in a directory with no project yet, it serves `nself_init` and the read-only tools; once `init` has created the project it lists every tool and sends `notifications/tools/list_changed`, and it does the same after a plugin is added or removed (for example the `ci` tools after `add ci`). Do not point one server at several projects. If you work on two projects, register two servers, each started from its own project directory. Tool results then never mix up which stack was changed.

## The confirm and dry-run gate

Expand Down
6 changes: 3 additions & 3 deletions .github/wiki/MCP-Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ After the path matches, the child rebuilds the registry from its mounted command

Running as a child keeps global state, `os.Exit` and the project operation lock identical to a typed command. There is no shell anywhere: every request value is exactly one argv element.

The **machine registry** is the v1.5 registry of the running binary with installed plugin commands mounted. It is the same in both compat modes ([[Compat-V15]]), so tool names and routes are the v1.5 shape in 1.4.x too. The plugin set is read when the server starts; install a plugin, then restart the server.
The **machine registry** is the v1.5 registry of the running binary with installed plugin commands mounted. It is the same in both compat modes ([[Compat-V15]]), so tool names and routes are the v1.5 shape in 1.4.x too. The plugin set is read when the server starts and again after any successful call that changed it: `nself mcp` then rebuilds the registry, replaces its tools and sends `notifications/tools/list_changed`, so tools of a plugin added in the session (`add ci`) appear without a restart. Started with no project, `nself mcp` lists `nself_init` and the read-only tools only, and lists the rest the same way once a project exists. Resources keep the registry of the server start.
Plugin commands are listed as tools like any other command, but a call that arrives while a secret bundle was restored is refused with `E421` because plugins do not yet support the secret-handoff protocol (D-0651). A machine-invoked plugin call that carries no secrets runs normally.

## Exposure rules
Expand Down Expand Up @@ -100,7 +100,7 @@ Any inherited value of these names is dropped first. The working directory is th

## Timeout and output limits

A document request times out after 300 seconds by default (the invoker takes the timeout as an option; the servers expose it as `--timeout`). The child leads its own process group. The group gets SIGTERM, and SIGKILL five seconds later or as soon as the child is gone, so grandchildren (docker compose, ssh, helpers) do not outlive a timed-out or cancelled request; the result is `E423`. An NDJSON request has no timeout and ends when the client disconnects. A long-polling command such as `nself ci runs wait` reads `NSELF_INVOKE_DEADLINE_MS` and returns before the kill.
A document request times out after 300 seconds by default (`nself mcp --timeout 15m` raises it for that server; the invoker takes the timeout as an option). The child leads its own process group. The group gets SIGTERM, and SIGKILL five seconds later or as soon as the child is gone, so grandchildren (docker compose, ssh, helpers) do not outlive a timed-out or cancelled request; the result is `E423`. An NDJSON request has no timeout and ends when the client disconnects. A long-polling command such as `nself ci runs wait` reads `NSELF_INVOKE_DEADLINE_MS` and returns before the kill.

The child's standard output is capped at 32 MiB and must be exactly one JSON object. Anything else is `E422` (exit class infra); its `cause` is the last 2 KiB of the child's standard error, with the request's secret values replaced and the usual redaction applied. A child envelope that carries `meta.deprecations` or `meta.warnings` passes through byte for byte.

Expand Down Expand Up @@ -141,7 +141,7 @@ The gate decides on the effective side effect of the request (flag escalation ap
- Consent and plan-id flags belong to the invoker. A request that sets one is refused with `E425` before anything runs.
- `read` runs.
- `write` without a plan form runs, with no consent flags.
- A command with a plan form and no `confirm`: the invoker runs the plan form once (`<path> --json --<plan.flag> ...`) and reads `data.plan_id` and `data.requires_confirmation` from the child's change plan. When `requires_confirmation` is true, or the class is `remote` or `destructive`, it returns a confirmation of kind `plan` whose `confirm` is the plan id. Otherwise it runs the command once with `--<id_flag>=<plan_id>`. A plan exec that fails returns the child's error envelope unchanged; a plan without a valid `plan_id` or `requires_confirmation` is `E422`. The plan exec and the run are two children, each with the full invocation timeout.
- A command with a plan form and no `confirm`: the invoker runs the plan form once (`<path> --json --<plan.flag> ...`) and reads `data.plan_id` and `data.requires_confirmation` from the child's change plan. When `requires_confirmation` is true, the class is `remote` or `destructive`, or the plan declares a `secrets-persist`, `certificates` or `trust-store` step (a first build that generates secrets, issues a certificate or installs the mkcert CA), it returns a confirmation of kind `plan` whose `confirm` is the plan id. Otherwise it runs the command once with `--<id_flag>=<plan_id>`. A plan exec that fails returns the child's error envelope unchanged; a plan without a valid `plan_id` or `requires_confirmation` is `E422`. The plan exec and the run are two children, each with the full invocation timeout.
- `remote` or `destructive` without a plan form and no `confirm`: a confirmation of kind `request`, whose `confirm` is a nonce.
- A server without a confirmation store refuses every remote and destructive command with `E421`.

Expand Down
Loading
Loading