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
4 changes: 2 additions & 2 deletions FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ migrations after upstream migrations.

47. Crew seats ask their Captain, not the person (#325, Jackson's 2026-09-26 decision). `apps/server/src/orchestration-v2/ProviderAdapter.ts` appends an optional `crewSeat` to `ProviderAdapterV2RuntimePolicy` beside `agentPersonaInstructions`. J5-owned `makeAgentPersonaRuntimePolicyResolver` (`j5/agents/agentPersonaRuntime.ts`), already the only resolver behind upstream `RuntimePolicy.ts`, asks J5-owned `makeCrewSeatLookup` (`j5/a2a/crewSeatRuntime.ts`) whether an `agent`/`mcp` thread holds a seat in a live Crew, through the Crew store built over the ambient SQL client (`RuntimePolicy.ts` is untouched and its layers gain no requirement; without a SQL client nothing is a seat, and an unreadable store logs and answers no). A seat's policy gets `crewSeat: true` and the ask-your-Captain rule appended to `agentPersonaInstructions`, so it lands after Codex's Default-mode "ask the user directly" text and Claude's system prompt without editing `CodexDeveloperInstructions.ts`. Two adapter appends consume the flag through J5-owned leaf `j5/a2a/crewSeatQuestions.ts`: `makeClaudeAdapterV2`'s `openQuery` spreads `j5ClaudeCrewSeatQueryOverrides(turnInput.runtimePolicy)` into `makeClaudeQueryOptions` (`disallowedTools: ["AskUserQuestion"]`, the SDK option that already existed but was never set), and `codexThreadRuntimeParams` spreads `j5CodexCrewSeatConfig(input.runtimePolicy)` into the thread `config` beside `mcp_servers` (dotted session overrides `features.default_mode_request_user_input = false` and `tools.experimental_request_user_input.enabled = false`, sent on thread start, resume, and fork only when the t3-code MCP session is attached). Cursor, Grok, OpenCode, Pi, ACP registry agents, and Antigravity are not supported on seats yet: they get only the seat brief's instruction (`spawnFirstTurnText` in `j5/a2a/spawnIds.ts`). Captains and every other thread keep their native question tools. Tests: `j5/a2a/crewSeatRuntime.test.ts` (seat, Captain, person thread, persona seat, archived Crew, no SQL client), `j5/a2a/crewSeatQuestions.test.ts` (Codex config and developer-text order), and one `ClaudeAdapterV2.test.ts` case, "withholds AskUserQuestion only from a Crew seat", on the existing wake harness. On every rebase, verify both spreads survive and that upstream has not renamed the Codex switches or added another native question tool.

48. Cross-server peering's scope (Jackson's 2026-09-16 ruling: the squadron id encapsulates the server and agents never address an environment; since 2026-10-02 agents see which server a participant lives on, by the server's own name, and still never manage one). `packages/contracts/src/auth.ts` appends the `a2a:peer` literal as `AuthA2APeerScope` to `AuthEnvironmentScope`, outside both `AuthStandardClientScopes` and `AuthAdministrativeScopes`, exactly as case 35 did for `a2a:send`: no pairing link and no administrative session carries it. Only the J5 peer credential route (`apps/server/src/j5/a2a/PeerHttp.ts`, behind `access:write`) mints it, bound by the session subject to one `peer:<environment id>`, and the peer routes authorize on that scope plus a registered peer. `packages/contracts/src/environment.ts` adds one optional capability key, `j5PeerPoll`, beside case 34's two, and `apps/server/src/environment/ServerEnvironment.ts` (with its test) reports it as true; it says a server has peering poll mode and the reachability routes, and the peering dialog offers a setup only when both servers publish it. Everything else is add-beside: migrations 23–27 (26 indexes the peer route probes; 27 indexes received sender labels by receipt time for the client identity read) 30 (poll mode: the peer table rebuilt with its link mode, the store grants, and the delivery rows' hand-out stamp) and 32 (a stored roster snapshot's fields renamed for peer protocol 2, where the wire names a project and no longer a Squadron), `PeerRegistryService.ts`, `PeerInboundService.ts`, `PeerDirectory.ts`, `PeerStoreService.ts` (the poll route's long poll), `PeerPoller.ts` (one loop per peer this server polls, started with the A2A runtime), `peerDeliveryBody.ts`, `peerRoster.ts`, `peerReachability.ts` (the origins the `addresses` route offers; it imports upstream's host helpers from `startupAccess.ts` without changing them), `peerProtocol.ts` (the one peer protocol version compare, used in both directions; the version is 2 since the wire fields were renamed, so two peered servers update together and an older one is named as the one to update), `PeerHttp.ts` entering through the case 9 aggregate (the J5 route files share `httpSupport.ts` for authentication and error shapes), the `peer` group in J5-owned `apps/server/src/j5/cli/a2a.ts`, and the wire contracts in `packages/contracts/src/j5.ts`. The peer layers are wired once in J5-owned `runtimeLayer.ts`, which gives them their own `FetchHttpClient` and takes `EnvironmentAuth` and `ServerEnvironment` from the server context, so the shared A2A runtime's requirements grow by those two upstream services; `ServerEnvironment`'s descriptor label is the name a server reports to its peers. One upstream-adjacent test moves with it: `apps/server/src/mcp/toolkits/worktree/registration.test.ts` (already J5-modified for `list_participants`) provides the empty `PeerDirectory` and a ledger stub for project titles, and expects `unread_peer_count` and `project_title`. The web side is one mount: `apps/web/src/components/settings/ConnectionsSettings.tsx` renders the J5-owned `PeerServersSettings` (from `apps/web/src/j5/peering/`) after the remote-environments section, gated by the page's existing `access:write` check, and imports nothing else from J5; the client helpers live in `packages/client-runtime/src/j5/http.ts`, `state.ts`, and the new `peering.ts` subpath export, which adds one `./j5/peering` entry to that package's exports map beside the existing J5 subpaths. On every rebase, verify the literal is still outside both bundles, `PAIRING_SCOPE_OPTIONS` in `ConnectionsSettings.tsx` still omits it, `runtimeLayer.ts` still provides the peer layers to the aggregate and the send service, and the single `PeerServersSettings` mount survives. Development databases that ran an earlier cut of this stack, where these migrations carried ids 14–16 and later 18–21, are disposable test state with no upgrade path: recreate them with `pr-env.sh --fresh`.
48. Cross-server peering's scope (Jackson's 2026-09-16 ruling: the squadron id encapsulates the server and agents never address an environment; since 2026-10-02 agents see which server a participant lives on, by the server's own name, and still never manage one). `packages/contracts/src/auth.ts` appends the `a2a:peer` literal as `AuthA2APeerScope` to `AuthEnvironmentScope`, outside both `AuthStandardClientScopes` and `AuthAdministrativeScopes`, exactly as case 35 did for `a2a:send`: no pairing link and no administrative session carries it. Only the J5 peer credential route (`apps/server/src/j5/a2a/PeerHttp.ts`, behind `access:write`) mints it, bound by the session subject to one `peer:<environment id>`, and the peer routes authorize on that scope plus a registered peer. `packages/contracts/src/environment.ts` adds one optional capability key, `j5PeerPoll`, beside case 34's two, and `apps/server/src/environment/ServerEnvironment.ts` (with its test) reports it as true; it says a server has peering poll mode and the reachability routes, and the peering dialog offers a setup only when both servers publish it. Everything else is add-beside: migrations 23–27 (26 indexes the peer route probes; 27 indexes received sender labels by receipt time for the client identity read) 30 (poll mode: the peer table rebuilt with its link mode, the store grants, and the delivery rows' hand-out stamp) and 32 (a stored roster snapshot's fields renamed for peer protocol 2, where the wire names a project and no longer a Squadron), `PeerRegistryService.ts`, `PeerInboundService.ts`, `PeerDirectory.ts`, `PeerStoreService.ts` (the poll route's long poll), `PeerPoller.ts` (one loop per peer this server polls, started with the A2A runtime), `peerDeliveryBody.ts`, `peerRoster.ts`, `peerReachability.ts` (the origins the `addresses` route offers; it imports upstream's host helpers from `startupAccess.ts` without changing them), `peerProtocol.ts` (the one peer protocol version compare, used in both directions; the version is 2 since the wire fields were renamed, so two peered servers update together and an older one is named as the one to update), `PeerHttp.ts` entering through the case 9 aggregate (the J5 route files share `httpSupport.ts` for authentication and error shapes), the `peer` group in J5-owned `apps/server/src/j5/cli/a2a.ts`, and the wire contracts in `packages/contracts/src/j5.ts`. The peer layers are wired once in J5-owned `runtimeLayer.ts`, which gives them their own `FetchHttpClient` and takes `EnvironmentAuth` and `ServerEnvironment` from the server context, so the shared A2A runtime's requirements grow by those two upstream services; `ServerEnvironment`'s descriptor label is the name a server reports to its peers. One upstream-adjacent test moves with it: `apps/server/src/mcp/toolkits/worktree/registration.test.ts` (already J5-modified for `list_participants`) provides the empty `PeerDirectory` and a ledger stub for project titles, and expects `unread_peer_count` and `project_title`. The web side is one mount: `apps/web/src/components/settings/ConnectionsSettings.tsx` renders the J5-owned `PeerServersSettings` (from `apps/web/src/j5/peering/`) after the remote-environments section, gated by the page's existing `access:write` check, and imports nothing else from J5; the client helpers live in `packages/client-runtime/src/j5/http.ts`, `state.ts`, and the new `peering.ts` subpath export, which adds one `./j5/peering` entry to that package's exports map beside the existing J5 subpaths. On every rebase, verify the literal is still outside both bundles, `PAIRING_SCOPE_OPTIONS` in `ConnectionsSettings.tsx` still omits it, `runtimeLayer.ts` still provides the peer layers to the aggregate and the send service, and the single `PeerServersSettings` mount survives. `docs/README.md` links the peering guide, `docs/user/j5-peering.md`, beside the other J5 user guides. Development databases that ran an earlier cut of this stack, where these migrations carried ids 14–16 and later 18–21, are disposable test state with no upgrade path: recreate them with `pr-env.sh --fresh`.

49. Composer playbook picker (#314, #320). `/playbook ` (at message start) and `@playbook:` (anywhere) open one playbook picker fed by the J5 library route. These are client-side discovery and text-insertion seams; execution follows case 45's ordinary message expansion.
- Detection: shared `composerTrigger.ts` and web `composer-logic.ts` append the `"slash-playbook"` kind and delegate line-start `/playbook <name>` detection to J5-owned `packages/shared/src/j5/playbookTrigger.ts`, exported through `packages/shared/package.json`; it matches the kebab-case name at the start of the message and stops before following text (#314). The J5 `detectAgentMention` hook, already called at token level from both, returns the same kind for `@playbook:` tokens with the raw token after the prefix as the query (`packages/shared/src/j5/playbookMention.ts`; no upstream line).
Expand Down Expand Up @@ -622,7 +622,7 @@ indicate approval. The deleted hook remains explicitly marked.
| `apps/web/src/components/settings/settingsSearch.ts` | N | 42–44 |
| `apps/web/src/components/settings/SettingsSidebarNav.tsx` | N | 42 |
| `apps/web/src/state/query.ts` | N | 42 |
| `docs/README.md` | N | 42, 45 |
| `docs/README.md` | N | 42, 45, 48 |
| `packages/client-runtime/src/state/runtime.test.ts` | N | 42 |
| `packages/contracts/src/auth.ts` | N | 35 |
| `apps/server/src/cloud/bootService.test.ts` | A | H, 50 |
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- [Usage and limits](./user/usage.md)
- [Planning artifacts](./user/artifacts.md)
- [Playbooks](./user/playbooks.md)
- [Connecting two J5 servers](./user/j5-peering.md)
- [Product usage data](./user/telemetry.md)
- [Remote access](./user/remote-access.md)
- [Running in the background](./user/background-service.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/j5/product/a2a/agent-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ An agent learns what it can do from its tools, and it reads a tool's description

**Events:** message and Exchange events in the ledger; delivery receipts follow asynchronously.

**Not delivered.** When the recipient's server refuses a message, or the message is cancelled before it was delivered, the sender gets a platform notice saying so, naming the recipient, its server and the reason: "Your message to <B> on Laptop was not delivered: Laptop refused it; the recipient is archived or does not accept messages from this sender." The reason is the platform's own words for each refusal it knows; any other is quoted on one line as what the server said. Removing a peer server cancels everything still waiting for it, with the reason that the server is no longer peered; a message the server may already hold is told it may not have been delivered: one a polling server had already picked up, or one sent directly whose answer never came back. A refused ask also ends its Exchange: the same notice says so, the Exchange is dropped as refused rather than as an archive, and the sender owes nothing and should not retry it.
**Not delivered.** When the recipient's server refuses a message, or the message is cancelled before it was delivered, the sender gets a platform notice saying so, naming the recipient, its server and the reason: "Your message to <B> on Laptop was not delivered: Laptop refused it; the recipient is archived or does not accept messages from this sender." The reason is the platform's own words for each refusal it knows; any other is quoted on one line as what the server said. Removing a peer server cancels everything still waiting for it, with the reason that the server is no longer peered; for a message the server may already hold, the sender is told it may not have been delivered: one a polling server had already picked up, or one sent directly whose answer never came back. A refused ask also ends its Exchange: the same notice says so, the Exchange is dropped as refused rather than as an archive, and the sender owes nothing and should not retry it.

### `list_participants`

Expand Down
Loading
Loading