From 5e164cf7a628cd428aeefe14b883ef2127ed3675 Mon Sep 17 00:00:00 2001 From: Carsten Koch Date: Sun, 4 Oct 2026 08:18:53 +0200 Subject: [PATCH] chore(release): v0.202.0 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT --- Cargo.lock | 30 +++++++------- Cargo.toml | 2 +- .../4gp2-held-answers-reach-their-caller.md | 25 ----------- changes/70dy-pm-talks-to-pm.md | 41 ------------------- changes/ewbj-tools-empty-is-a-gate.md | 26 ------------ docs/generated/commands.json | 2 +- docs/generated/man/nxf.1 | 4 +- release-notes.json | 28 +++++++++++++ 8 files changed, 47 insertions(+), 111 deletions(-) delete mode 100644 changes/4gp2-held-answers-reach-their-caller.md delete mode 100644 changes/70dy-pm-talks-to-pm.md delete mode 100644 changes/ewbj-tools-empty-is-a-gate.md diff --git a/Cargo.lock b/Cargo.lock index b7e701b..fb8e431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2237,7 +2237,7 @@ dependencies = [ [[package]] name = "nexus-chat" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "clap", @@ -2266,7 +2266,7 @@ dependencies = [ [[package]] name = "nexus-flow-cli" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "axum", @@ -2304,7 +2304,7 @@ dependencies = [ [[package]] name = "nexus-flow-core" -version = "0.201.0" +version = "0.202.0" dependencies = [ "automerge", "nxs-foundation", @@ -2314,7 +2314,7 @@ dependencies = [ [[package]] name = "nexus-flow-facade" -version = "0.201.0" +version = "0.202.0" dependencies = [ "inventory", "nexus-flow-core", @@ -2330,7 +2330,7 @@ dependencies = [ [[package]] name = "nexus-memory" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "clap", @@ -2398,7 +2398,7 @@ dependencies = [ [[package]] name = "nxs" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "axum", @@ -2437,7 +2437,7 @@ dependencies = [ [[package]] name = "nxs-foundation" -version = "0.201.0" +version = "0.202.0" dependencies = [ "base64", "ed25519-dalek", @@ -2452,7 +2452,7 @@ dependencies = [ [[package]] name = "nxs-guide" -version = "0.201.0" +version = "0.202.0" dependencies = [ "include_dir", "nxs-foundation", @@ -2461,7 +2461,7 @@ dependencies = [ [[package]] name = "nxs-init" -version = "0.201.0" +version = "0.202.0" dependencies = [ "inventory", "nxs-foundation", @@ -2474,7 +2474,7 @@ dependencies = [ [[package]] name = "nxs-server" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "aws-config", @@ -2500,7 +2500,7 @@ dependencies = [ [[package]] name = "nxs-service" -version = "0.201.0" +version = "0.202.0" dependencies = [ "directories", "libc", @@ -2515,7 +2515,7 @@ dependencies = [ [[package]] name = "nxs-sync" -version = "0.201.0" +version = "0.202.0" dependencies = [ "base64", "flate2", @@ -2530,7 +2530,7 @@ dependencies = [ [[package]] name = "nxs-test-support" -version = "0.201.0" +version = "0.202.0" dependencies = [ "assert_cmd", "clap", @@ -2541,7 +2541,7 @@ dependencies = [ [[package]] name = "nxs-ui" -version = "0.201.0" +version = "0.202.0" dependencies = [ "anstream", "anstyle", @@ -2693,7 +2693,7 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plugin-probe" -version = "0.201.0" +version = "0.202.0" dependencies = [ "inventory", "nexus-flow-core", diff --git a/Cargo.toml b/Cargo.toml index 8ba31dd..30d9eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ exclude = ["examples/tauri-board/src-tauri"] # (clap). The release tag `v` is the truth and CI enforces tag == version # fail-closed. See docs/specs/release-management.md §4.1. [workspace.package] -version = "0.201.0" +version = "0.202.0" # Trim the debug build cache (nexus-flow-k1i). `target/debug` had grown to ~24 GB of `.o`/DWARF # in `deps/` because the default `debug = true` emits FULL debug info — and on macOS diff --git a/changes/4gp2-held-answers-reach-their-caller.md b/changes/4gp2-held-answers-reach-their-caller.md deleted file mode 100644 index cbfd0ba..0000000 --- a/changes/4gp2-held-answers-reach-their-caller.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: fixed -facade: changed ---- -[en] -An answer that reaches a caller while it is still finishing its turn is now delivered. On the -command line the background service was handed the delivery as a channel deadline on a session id -("no such thread"), so a held answer was never handed over; and the caller's sidecar, seeing its -sub-round already answered, reminded it and then posted a substitute reply in its name. A sub-round -whose answer is held for its commissioner now counts as still in flight (`waiting_on_sub_round` in -`nxc status --json` and on the facade). Also fixed: a persona that declares no `tools:` and is woken -with an answer it still has to pass on is granted its `nxc reply` (the wake carries the obligation it -still has), and a session spawned by a development build resolves that build's service home, not the -installed one. -[de] -Eine Antwort, die einen Aufrufer erreicht, während er seinen Zug noch beendet, wird jetzt -zugestellt. Auf der Kommandozeile bekam der Hintergrunddienst die Zustellung als Kanal-Frist auf -eine Sitzungs-ID („no such thread“), eine zurückgehaltene Antwort wurde also nie übergeben; und die -Sidecar des Aufrufers sah seine Unterrunde schon beantwortet, erinnerte ihn und postete dann eine -Ersatzantwort in seinem Namen. Eine Unterrunde, deren Antwort für ihren Auftraggeber zurückgehalten -wird, zählt jetzt weiter als unterwegs (`waiting_on_sub_round` in `nxc status --json` und in der -Fassade). Außerdem behoben: Eine Persona ohne `tools:`, die mit einer Antwort geweckt wird, die sie -noch weitergeben muss, darf ihr `nxc reply` ausführen (die Weckung trägt die Pflicht mit, die sie -noch hat), und eine Sitzung, die ein Entwicklungs-Build startet, nutzt dessen Dienst-Verzeichnis, -nicht das installierte. diff --git a/changes/70dy-pm-talks-to-pm.md b/changes/70dy-pm-talks-to-pm.md deleted file mode 100644 index b7ebac7..0000000 --- a/changes/70dy-pm-talks-to-pm.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -type: added -facade: breaking ---- -[en] -A persona can commission a persona of another workspace on the same machine, and the answer comes -back. `nxc send --to //` records the commission in the caller's own workspace -and hands over that one thread; the other workspace checks access, starts its persona in its own -working copy, and the answer — or a question, which always goes to whoever commissioned — wakes the -caller. Only the border thread crosses. Access is the receiver's: `addressable.external` admits a -role from trusted workspaces (`"*/pm"`, `nxsflow/manufakt-io/pm`), and without it nothing comes in. -New: `nxs name` (a workspace's stored `/` name), `nxs sync trust add --workspace -/` (trust a neighbouring workspace by name; needed on both sides), and `nxc status` -showing a border thread in both workspaces with the other side and its state (submitted, working, -input-required, completed, rejected, canceled). Two hours without a sign of life cancel it; -`nxc withdraw` takes it back on both sides. An engine older than this release cannot load a persona -file that carries `external:` — add it only once every reader of the repository is on this version. -For embedding apps: `EngineConfig::peers` and `Ctx::peers` (the host's way to reach other -workspaces; `None` keeps everything as before), `Engine::handover`, `Addressable::OnlyWithExternal`, -`Coordinator::Border`, and new `border` fields on `Refs`, `SendToReceipt`, `ReplyReceipt` and -`StatusThread` — a struct literal of `EngineConfig`, `Ctx`, `Adapter` or `Refs` without -`..Default::default()` needs the new field. -[de] -Eine Persona kann eine Persona eines anderen Arbeitsbereichs auf derselben Maschine beauftragen, -und die Antwort kommt zurück. `nxc send --to //` legt den Auftrag im -eigenen Arbeitsbereich ab und übergibt genau diesen einen Faden; der andere Arbeitsbereich prüft den -Zugang, startet seine Persona in seiner eigenen Arbeitskopie, und die Antwort — oder eine -Rückfrage, die immer an den Auftraggeber geht — weckt den Aufrufer. Nur der Grenzfaden geht hinüber. -Den Zugang bestimmt der Empfänger: `addressable.external` lässt eine Rolle aus vertrauten -Arbeitsbereichen zu (`"*/pm"`, `nxsflow/manufakt-io/pm`), ohne das Feld kommt nichts herein. Neu: -`nxs name` (der gespeicherte Name `/` eines Arbeitsbereichs), `nxs sync trust add ---workspace /` (einem benachbarten Arbeitsbereich beim Namen vertrauen; auf beiden -Seiten nötig) und `nxc status`, das einen Grenzfaden in beiden Arbeitsbereichen mit der Gegenseite -und seinem Zustand zeigt (submitted, working, input-required, completed, rejected, canceled). Zwei -Stunden ohne Lebenszeichen brechen ihn ab; `nxc withdraw` zieht ihn auf beiden Seiten zurück. Eine -Engine, die älter ist als dieses Release, kann eine Persona-Datei mit `external:` nicht laden — -setzen Sie das Feld erst, wenn alle Leser des Repositorys diesen Stand haben. Für einbettende Apps: -`EngineConfig::peers` und `Ctx::peers` (der Weg des Hosts zu anderen Arbeitsbereichen; `None` lässt -alles wie bisher), `Engine::handover`, `Addressable::OnlyWithExternal`, `Coordinator::Border` und neue -Felder `border` an `Refs`, `SendToReceipt`, `ReplyReceipt` und `StatusThread` — ein Struct-Literal -von `EngineConfig`, `Ctx`, `Adapter` oder `Refs` ohne `..Default::default()` braucht das neue Feld. diff --git a/changes/ewbj-tools-empty-is-a-gate.md b/changes/ewbj-tools-empty-is-a-gate.md deleted file mode 100644 index 4ce55be..0000000 --- a/changes/ewbj-tools-empty-is-a-gate.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: fixed -facade: changed ---- -[en] -Safety fix: a persona declared with `tools: []` can no longer run arbitrary shell commands when it -owes a reply. Until now the engine granted every such session the bare, auto-approved `Bash` so that -it could answer, which gave a persona declared to have no tools a full shell (`gh pr merge`, -`git push --force`, a release). It now grants `Bash(nxc reply:*)`: the reply runs, every other -command needs an approval nobody is there to give and is refused. A persona whose `tools:` is absent, -or lists `Bash`, behaves as before; one that declares `Bash(nxc reply:*)` itself now stays that -narrow. For an embedding app's own worker: `RoleSpec::granted_tools` (`grantedTools` in the sidecar -spec) can now carry a scoped permission rule rather than a tool name — put the tool it names into the -SDK's `tools` and the rule itself into `allowedTools`, as the bundled sidecar does. -[de] -Sicherheitskorrektur: Eine Persona mit `tools: []` kann keine beliebigen Shell-Befehle mehr -ausführen, wenn sie eine Antwort schuldet. Bisher gewährte die Engine jeder solchen Sitzung das -nackte, automatisch freigegebene `Bash`, damit sie antworten konnte — eine Persona ohne Werkzeuge -hatte damit eine volle Shell (`gh pr merge`, `git push --force`, ein Release). Jetzt gewährt sie -`Bash(nxc reply:*)`: Die Antwort läuft, jeder andere Befehl braucht eine Freigabe, die niemand -erteilen kann, und wird abgewiesen. Eine Persona ohne `tools:` oder mit `Bash` in der Liste verhält -sich wie bisher; eine, die selbst `Bash(nxc reply:*)` deklariert, bleibt jetzt so eng. Für den -eigenen Worker einer einbettenden App: `RoleSpec::granted_tools` (`grantedTools` in der -Sidecar-Spezifikation) kann jetzt eine eingeschränkte Berechtigungsregel statt eines Werkzeugnamens -tragen — das genannte Werkzeug gehört in `tools` des SDK, die Regel selbst in `allowedTools`, wie es -die mitgelieferte Sidecar tut. diff --git a/docs/generated/commands.json b/docs/generated/commands.json index a4bc0db..7405432 100644 --- a/docs/generated/commands.json +++ b/docs/generated/commands.json @@ -1,5 +1,5 @@ { - "version": "0.201.0", + "version": "0.202.0", "command": { "name": "nxf", "about": "nexus-flow agent CLI", diff --git a/docs/generated/man/nxf.1 b/docs/generated/man/nxf.1 index 24aa6f5..974a766 100644 --- a/docs/generated/man/nxf.1 +++ b/docs/generated/man/nxf.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH nxf 1 "nxf 0.201.0" +.TH nxf 1 "nxf 0.202.0" .SH NAME nxf \- nexus\-flow agent CLI .SH SYNOPSIS @@ -106,4 +106,4 @@ Print an embedded, offline guide. Omit the topic to list the available ones nxf\-help(1) Print this message or the help of the given subcommand(s) .SH VERSION -v0.201.0 +v0.202.0 diff --git a/release-notes.json b/release-notes.json index 35a3887..a8fd3b5 100644 --- a/release-notes.json +++ b/release-notes.json @@ -2,6 +2,34 @@ "channels": { "alpha": [], "beta": [ + { + "version": "0.202.0", + "date": "2026-10-04", + "items": [ + { + "type": "fixed", + "en": "An answer that reaches a caller while it is still finishing its turn is now delivered. On the\ncommand line the background service was handed the delivery as a channel deadline on a session id\n(\"no such thread\"), so a held answer was never handed over; and the caller's sidecar, seeing its\nsub-round already answered, reminded it and then posted a substitute reply in its name. A sub-round\nwhose answer is held for its commissioner now counts as still in flight (`waiting_on_sub_round` in\n`nxc status --json` and on the facade). Also fixed: a persona that declares no `tools:` and is woken\nwith an answer it still has to pass on is granted its `nxc reply` (the wake carries the obligation it\nstill has), and a session spawned by a development build resolves that build's service home, not the\ninstalled one.", + "de": "Eine Antwort, die einen Aufrufer erreicht, während er seinen Zug noch beendet, wird jetzt\nzugestellt. Auf der Kommandozeile bekam der Hintergrunddienst die Zustellung als Kanal-Frist auf\neine Sitzungs-ID („no such thread“), eine zurückgehaltene Antwort wurde also nie übergeben; und die\nSidecar des Aufrufers sah seine Unterrunde schon beantwortet, erinnerte ihn und postete dann eine\nErsatzantwort in seinem Namen. Eine Unterrunde, deren Antwort für ihren Auftraggeber zurückgehalten\nwird, zählt jetzt weiter als unterwegs (`waiting_on_sub_round` in `nxc status --json` und in der\nFassade). Außerdem behoben: Eine Persona ohne `tools:`, die mit einer Antwort geweckt wird, die sie\nnoch weitergeben muss, darf ihr `nxc reply` ausführen (die Weckung trägt die Pflicht mit, die sie\nnoch hat), und eine Sitzung, die ein Entwicklungs-Build startet, nutzt dessen Dienst-Verzeichnis,\nnicht das installierte.", + "facade": "changed" + }, + { + "type": "added", + "en": "A persona can commission a persona of another workspace on the same machine, and the answer comes\nback. `nxc send --to //` records the commission in the caller's own workspace\nand hands over that one thread; the other workspace checks access, starts its persona in its own\nworking copy, and the answer — or a question, which always goes to whoever commissioned — wakes the\ncaller. Only the border thread crosses. Access is the receiver's: `addressable.external` admits a\nrole from trusted workspaces (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), and without it nothing comes in.\nNew: `nxs name` (a workspace's stored `/` name), `nxs sync trust add --workspace\n/` (trust a neighbouring workspace by name; needed on both sides), and `nxc status`\nshowing a border thread in both workspaces with the other side and its state (submitted, working,\ninput-required, completed, rejected, canceled). Two hours without a sign of life cancel it;\n`nxc withdraw` takes it back on both sides. An engine older than this release cannot load a persona\nfile that carries `external:` — add it only once every reader of the repository is on this version.\nFor embedding apps: `EngineConfig::peers` and `Ctx::peers` (the host's way to reach other\nworkspaces; `None` keeps everything as before), `Engine::handover`, `Addressable::OnlyWithExternal`,\n`Coordinator::Border`, and new `border` fields on `Refs`, `SendToReceipt`, `ReplyReceipt` and\n`StatusThread` — a struct literal of `EngineConfig`, `Ctx`, `Adapter` or `Refs` without\n`..Default::default()` needs the new field.", + "de": "Eine Persona kann eine Persona eines anderen Arbeitsbereichs auf derselben Maschine beauftragen,\nund die Antwort kommt zurück. `nxc send --to //` legt den Auftrag im\neigenen Arbeitsbereich ab und übergibt genau diesen einen Faden; der andere Arbeitsbereich prüft den\nZugang, startet seine Persona in seiner eigenen Arbeitskopie, und die Antwort — oder eine\nRückfrage, die immer an den Auftraggeber geht — weckt den Aufrufer. Nur der Grenzfaden geht hinüber.\nDen Zugang bestimmt der Empfänger: `addressable.external` lässt eine Rolle aus vertrauten\nArbeitsbereichen zu (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), ohne das Feld kommt nichts herein. Neu:\n`nxs name` (der gespeicherte Name `/` eines Arbeitsbereichs), `nxs sync trust add\n--workspace /` (einem benachbarten Arbeitsbereich beim Namen vertrauen; auf beiden\nSeiten nötig) und `nxc status`, das einen Grenzfaden in beiden Arbeitsbereichen mit der Gegenseite\nund seinem Zustand zeigt (submitted, working, input-required, completed, rejected, canceled). Zwei\nStunden ohne Lebenszeichen brechen ihn ab; `nxc withdraw` zieht ihn auf beiden Seiten zurück. Eine\nEngine, die älter ist als dieses Release, kann eine Persona-Datei mit `external:` nicht laden —\nsetzen Sie das Feld erst, wenn alle Leser des Repositorys diesen Stand haben. Für einbettende Apps:\n`EngineConfig::peers` und `Ctx::peers` (der Weg des Hosts zu anderen Arbeitsbereichen; `None` lässt\nalles wie bisher), `Engine::handover`, `Addressable::OnlyWithExternal`, `Coordinator::Border` und neue\nFelder `border` an `Refs`, `SendToReceipt`, `ReplyReceipt` und `StatusThread` — ein Struct-Literal\nvon `EngineConfig`, `Ctx`, `Adapter` oder `Refs` ohne `..Default::default()` braucht das neue Feld.", + "facade": "breaking" + }, + { + "type": "fixed", + "en": "Safety fix: a persona declared with `tools: []` can no longer run arbitrary shell commands when it\nowes a reply. Until now the engine granted every such session the bare, auto-approved `Bash` so that\nit could answer, which gave a persona declared to have no tools a full shell (`gh pr merge`,\n`git push --force`, a release). It now grants `Bash(nxc reply:*)`: the reply runs, every other\ncommand needs an approval nobody is there to give and is refused. A persona whose `tools:` is absent,\nor lists `Bash`, behaves as before; one that declares `Bash(nxc reply:*)` itself now stays that\nnarrow. For an embedding app's own worker: `RoleSpec::granted_tools` (`grantedTools` in the sidecar\nspec) can now carry a scoped permission rule rather than a tool name — put the tool it names into the\nSDK's `tools` and the rule itself into `allowedTools`, as the bundled sidecar does.", + "de": "Sicherheitskorrektur: Eine Persona mit `tools: []` kann keine beliebigen Shell-Befehle mehr\nausführen, wenn sie eine Antwort schuldet. Bisher gewährte die Engine jeder solchen Sitzung das\nnackte, automatisch freigegebene `Bash`, damit sie antworten konnte — eine Persona ohne Werkzeuge\nhatte damit eine volle Shell (`gh pr merge`, `git push --force`, ein Release). Jetzt gewährt sie\n`Bash(nxc reply:*)`: Die Antwort läuft, jeder andere Befehl braucht eine Freigabe, die niemand\nerteilen kann, und wird abgewiesen. Eine Persona ohne `tools:` oder mit `Bash` in der Liste verhält\nsich wie bisher; eine, die selbst `Bash(nxc reply:*)` deklariert, bleibt jetzt so eng. Für den\neigenen Worker einer einbettenden App: `RoleSpec::granted_tools` (`grantedTools` in der\nSidecar-Spezifikation) kann jetzt eine eingeschränkte Berechtigungsregel statt eines Werkzeugnamens\ntragen — das genannte Werkzeug gehört in `tools` des SDK, die Regel selbst in `allowedTools`, wie es\ndie mitgelieferte Sidecar tut.", + "facade": "changed" + } + ], + "notes": { + "en": "### Added\n- A persona can commission a persona of another workspace on the same machine, and the answer comes\nback. `nxc send --to //` records the commission in the caller's own workspace\nand hands over that one thread; the other workspace checks access, starts its persona in its own\nworking copy, and the answer — or a question, which always goes to whoever commissioned — wakes the\ncaller. Only the border thread crosses. Access is the receiver's: `addressable.external` admits a\nrole from trusted workspaces (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), and without it nothing comes in.\nNew: `nxs name` (a workspace's stored `/` name), `nxs sync trust add --workspace\n/` (trust a neighbouring workspace by name; needed on both sides), and `nxc status`\nshowing a border thread in both workspaces with the other side and its state (submitted, working,\ninput-required, completed, rejected, canceled). Two hours without a sign of life cancel it;\n`nxc withdraw` takes it back on both sides. An engine older than this release cannot load a persona\nfile that carries `external:` — add it only once every reader of the repository is on this version.\nFor embedding apps: `EngineConfig::peers` and `Ctx::peers` (the host's way to reach other\nworkspaces; `None` keeps everything as before), `Engine::handover`, `Addressable::OnlyWithExternal`,\n`Coordinator::Border`, and new `border` fields on `Refs`, `SendToReceipt`, `ReplyReceipt` and\n`StatusThread` — a struct literal of `EngineConfig`, `Ctx`, `Adapter` or `Refs` without\n`..Default::default()` needs the new field.\n\n### Fixed\n- An answer that reaches a caller while it is still finishing its turn is now delivered. On the\ncommand line the background service was handed the delivery as a channel deadline on a session id\n(\"no such thread\"), so a held answer was never handed over; and the caller's sidecar, seeing its\nsub-round already answered, reminded it and then posted a substitute reply in its name. A sub-round\nwhose answer is held for its commissioner now counts as still in flight (`waiting_on_sub_round` in\n`nxc status --json` and on the facade). Also fixed: a persona that declares no `tools:` and is woken\nwith an answer it still has to pass on is granted its `nxc reply` (the wake carries the obligation it\nstill has), and a session spawned by a development build resolves that build's service home, not the\ninstalled one.\n- Safety fix: a persona declared with `tools: []` can no longer run arbitrary shell commands when it\nowes a reply. Until now the engine granted every such session the bare, auto-approved `Bash` so that\nit could answer, which gave a persona declared to have no tools a full shell (`gh pr merge`,\n`git push --force`, a release). It now grants `Bash(nxc reply:*)`: the reply runs, every other\ncommand needs an approval nobody is there to give and is refused. A persona whose `tools:` is absent,\nor lists `Bash`, behaves as before; one that declares `Bash(nxc reply:*)` itself now stays that\nnarrow. For an embedding app's own worker: `RoleSpec::granted_tools` (`grantedTools` in the sidecar\nspec) can now carry a scoped permission rule rather than a tool name — put the tool it names into the\nSDK's `tools` and the rule itself into `allowedTools`, as the bundled sidecar does.\n\n### Facade Contract\n- `changed` · An answer that reaches a caller while it is still finishing its turn is now delivered. On the\ncommand line the background service was handed the delivery as a channel deadline on a session id\n(\"no such thread\"), so a held answer was never handed over; and the caller's sidecar, seeing its\nsub-round already answered, reminded it and then posted a substitute reply in its name. A sub-round\nwhose answer is held for its commissioner now counts as still in flight (`waiting_on_sub_round` in\n`nxc status --json` and on the facade). Also fixed: a persona that declares no `tools:` and is woken\nwith an answer it still has to pass on is granted its `nxc reply` (the wake carries the obligation it\nstill has), and a session spawned by a development build resolves that build's service home, not the\ninstalled one.\n- `breaking` · A persona can commission a persona of another workspace on the same machine, and the answer comes\nback. `nxc send --to //` records the commission in the caller's own workspace\nand hands over that one thread; the other workspace checks access, starts its persona in its own\nworking copy, and the answer — or a question, which always goes to whoever commissioned — wakes the\ncaller. Only the border thread crosses. Access is the receiver's: `addressable.external` admits a\nrole from trusted workspaces (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), and without it nothing comes in.\nNew: `nxs name` (a workspace's stored `/` name), `nxs sync trust add --workspace\n/` (trust a neighbouring workspace by name; needed on both sides), and `nxc status`\nshowing a border thread in both workspaces with the other side and its state (submitted, working,\ninput-required, completed, rejected, canceled). Two hours without a sign of life cancel it;\n`nxc withdraw` takes it back on both sides. An engine older than this release cannot load a persona\nfile that carries `external:` — add it only once every reader of the repository is on this version.\nFor embedding apps: `EngineConfig::peers` and `Ctx::peers` (the host's way to reach other\nworkspaces; `None` keeps everything as before), `Engine::handover`, `Addressable::OnlyWithExternal`,\n`Coordinator::Border`, and new `border` fields on `Refs`, `SendToReceipt`, `ReplyReceipt` and\n`StatusThread` — a struct literal of `EngineConfig`, `Ctx`, `Adapter` or `Refs` without\n`..Default::default()` needs the new field.\n- `changed` · Safety fix: a persona declared with `tools: []` can no longer run arbitrary shell commands when it\nowes a reply. Until now the engine granted every such session the bare, auto-approved `Bash` so that\nit could answer, which gave a persona declared to have no tools a full shell (`gh pr merge`,\n`git push --force`, a release). It now grants `Bash(nxc reply:*)`: the reply runs, every other\ncommand needs an approval nobody is there to give and is refused. A persona whose `tools:` is absent,\nor lists `Bash`, behaves as before; one that declares `Bash(nxc reply:*)` itself now stays that\nnarrow. For an embedding app's own worker: `RoleSpec::granted_tools` (`grantedTools` in the sidecar\nspec) can now carry a scoped permission rule rather than a tool name — put the tool it names into the\nSDK's `tools` and the rule itself into `allowedTools`, as the bundled sidecar does.", + "de": "### Neu\n- Eine Persona kann eine Persona eines anderen Arbeitsbereichs auf derselben Maschine beauftragen,\nund die Antwort kommt zurück. `nxc send --to //` legt den Auftrag im\neigenen Arbeitsbereich ab und übergibt genau diesen einen Faden; der andere Arbeitsbereich prüft den\nZugang, startet seine Persona in seiner eigenen Arbeitskopie, und die Antwort — oder eine\nRückfrage, die immer an den Auftraggeber geht — weckt den Aufrufer. Nur der Grenzfaden geht hinüber.\nDen Zugang bestimmt der Empfänger: `addressable.external` lässt eine Rolle aus vertrauten\nArbeitsbereichen zu (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), ohne das Feld kommt nichts herein. Neu:\n`nxs name` (der gespeicherte Name `/` eines Arbeitsbereichs), `nxs sync trust add\n--workspace /` (einem benachbarten Arbeitsbereich beim Namen vertrauen; auf beiden\nSeiten nötig) und `nxc status`, das einen Grenzfaden in beiden Arbeitsbereichen mit der Gegenseite\nund seinem Zustand zeigt (submitted, working, input-required, completed, rejected, canceled). Zwei\nStunden ohne Lebenszeichen brechen ihn ab; `nxc withdraw` zieht ihn auf beiden Seiten zurück. Eine\nEngine, die älter ist als dieses Release, kann eine Persona-Datei mit `external:` nicht laden —\nsetzen Sie das Feld erst, wenn alle Leser des Repositorys diesen Stand haben. Für einbettende Apps:\n`EngineConfig::peers` und `Ctx::peers` (der Weg des Hosts zu anderen Arbeitsbereichen; `None` lässt\nalles wie bisher), `Engine::handover`, `Addressable::OnlyWithExternal`, `Coordinator::Border` und neue\nFelder `border` an `Refs`, `SendToReceipt`, `ReplyReceipt` und `StatusThread` — ein Struct-Literal\nvon `EngineConfig`, `Ctx`, `Adapter` oder `Refs` ohne `..Default::default()` braucht das neue Feld.\n\n### Behoben\n- Eine Antwort, die einen Aufrufer erreicht, während er seinen Zug noch beendet, wird jetzt\nzugestellt. Auf der Kommandozeile bekam der Hintergrunddienst die Zustellung als Kanal-Frist auf\neine Sitzungs-ID („no such thread“), eine zurückgehaltene Antwort wurde also nie übergeben; und die\nSidecar des Aufrufers sah seine Unterrunde schon beantwortet, erinnerte ihn und postete dann eine\nErsatzantwort in seinem Namen. Eine Unterrunde, deren Antwort für ihren Auftraggeber zurückgehalten\nwird, zählt jetzt weiter als unterwegs (`waiting_on_sub_round` in `nxc status --json` und in der\nFassade). Außerdem behoben: Eine Persona ohne `tools:`, die mit einer Antwort geweckt wird, die sie\nnoch weitergeben muss, darf ihr `nxc reply` ausführen (die Weckung trägt die Pflicht mit, die sie\nnoch hat), und eine Sitzung, die ein Entwicklungs-Build startet, nutzt dessen Dienst-Verzeichnis,\nnicht das installierte.\n- Sicherheitskorrektur: Eine Persona mit `tools: []` kann keine beliebigen Shell-Befehle mehr\nausführen, wenn sie eine Antwort schuldet. Bisher gewährte die Engine jeder solchen Sitzung das\nnackte, automatisch freigegebene `Bash`, damit sie antworten konnte — eine Persona ohne Werkzeuge\nhatte damit eine volle Shell (`gh pr merge`, `git push --force`, ein Release). Jetzt gewährt sie\n`Bash(nxc reply:*)`: Die Antwort läuft, jeder andere Befehl braucht eine Freigabe, die niemand\nerteilen kann, und wird abgewiesen. Eine Persona ohne `tools:` oder mit `Bash` in der Liste verhält\nsich wie bisher; eine, die selbst `Bash(nxc reply:*)` deklariert, bleibt jetzt so eng. Für den\neigenen Worker einer einbettenden App: `RoleSpec::granted_tools` (`grantedTools` in der\nSidecar-Spezifikation) kann jetzt eine eingeschränkte Berechtigungsregel statt eines Werkzeugnamens\ntragen — das genannte Werkzeug gehört in `tools` des SDK, die Regel selbst in `allowedTools`, wie es\ndie mitgelieferte Sidecar tut.\n\n### Facade-Kontrakt\n- `changed` · Eine Antwort, die einen Aufrufer erreicht, während er seinen Zug noch beendet, wird jetzt\nzugestellt. Auf der Kommandozeile bekam der Hintergrunddienst die Zustellung als Kanal-Frist auf\neine Sitzungs-ID („no such thread“), eine zurückgehaltene Antwort wurde also nie übergeben; und die\nSidecar des Aufrufers sah seine Unterrunde schon beantwortet, erinnerte ihn und postete dann eine\nErsatzantwort in seinem Namen. Eine Unterrunde, deren Antwort für ihren Auftraggeber zurückgehalten\nwird, zählt jetzt weiter als unterwegs (`waiting_on_sub_round` in `nxc status --json` und in der\nFassade). Außerdem behoben: Eine Persona ohne `tools:`, die mit einer Antwort geweckt wird, die sie\nnoch weitergeben muss, darf ihr `nxc reply` ausführen (die Weckung trägt die Pflicht mit, die sie\nnoch hat), und eine Sitzung, die ein Entwicklungs-Build startet, nutzt dessen Dienst-Verzeichnis,\nnicht das installierte.\n- `breaking` · Eine Persona kann eine Persona eines anderen Arbeitsbereichs auf derselben Maschine beauftragen,\nund die Antwort kommt zurück. `nxc send --to //` legt den Auftrag im\neigenen Arbeitsbereich ab und übergibt genau diesen einen Faden; der andere Arbeitsbereich prüft den\nZugang, startet seine Persona in seiner eigenen Arbeitskopie, und die Antwort — oder eine\nRückfrage, die immer an den Auftraggeber geht — weckt den Aufrufer. Nur der Grenzfaden geht hinüber.\nDen Zugang bestimmt der Empfänger: `addressable.external` lässt eine Rolle aus vertrauten\nArbeitsbereichen zu (`\"*/pm\"`, `nxsflow/manufakt-io/pm`), ohne das Feld kommt nichts herein. Neu:\n`nxs name` (der gespeicherte Name `/` eines Arbeitsbereichs), `nxs sync trust add\n--workspace /` (einem benachbarten Arbeitsbereich beim Namen vertrauen; auf beiden\nSeiten nötig) und `nxc status`, das einen Grenzfaden in beiden Arbeitsbereichen mit der Gegenseite\nund seinem Zustand zeigt (submitted, working, input-required, completed, rejected, canceled). Zwei\nStunden ohne Lebenszeichen brechen ihn ab; `nxc withdraw` zieht ihn auf beiden Seiten zurück. Eine\nEngine, die älter ist als dieses Release, kann eine Persona-Datei mit `external:` nicht laden —\nsetzen Sie das Feld erst, wenn alle Leser des Repositorys diesen Stand haben. Für einbettende Apps:\n`EngineConfig::peers` und `Ctx::peers` (der Weg des Hosts zu anderen Arbeitsbereichen; `None` lässt\nalles wie bisher), `Engine::handover`, `Addressable::OnlyWithExternal`, `Coordinator::Border` und neue\nFelder `border` an `Refs`, `SendToReceipt`, `ReplyReceipt` und `StatusThread` — ein Struct-Literal\nvon `EngineConfig`, `Ctx`, `Adapter` oder `Refs` ohne `..Default::default()` braucht das neue Feld.\n- `changed` · Sicherheitskorrektur: Eine Persona mit `tools: []` kann keine beliebigen Shell-Befehle mehr\nausführen, wenn sie eine Antwort schuldet. Bisher gewährte die Engine jeder solchen Sitzung das\nnackte, automatisch freigegebene `Bash`, damit sie antworten konnte — eine Persona ohne Werkzeuge\nhatte damit eine volle Shell (`gh pr merge`, `git push --force`, ein Release). Jetzt gewährt sie\n`Bash(nxc reply:*)`: Die Antwort läuft, jeder andere Befehl braucht eine Freigabe, die niemand\nerteilen kann, und wird abgewiesen. Eine Persona ohne `tools:` oder mit `Bash` in der Liste verhält\nsich wie bisher; eine, die selbst `Bash(nxc reply:*)` deklariert, bleibt jetzt so eng. Für den\neigenen Worker einer einbettenden App: `RoleSpec::granted_tools` (`grantedTools` in der\nSidecar-Spezifikation) kann jetzt eine eingeschränkte Berechtigungsregel statt eines Werkzeugnamens\ntragen — das genannte Werkzeug gehört in `tools` des SDK, die Regel selbst in `allowedTools`, wie es\ndie mitgelieferte Sidecar tut." + } + }, { "version": "0.201.0", "date": "2026-10-03",