Repository navigation
chore(lint): enforce effectFnOpportunity - #25099
Conversation
6a7e430 to
1d662e5
Compare
a19b65b to
09d1eaa
Compare
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
09d1eaa to
800f155
Compare
5a4b2e3 to
71140aa
Compare
800f155 to
816dba6
Compare
3c6d6cd to
b9fc278
Compare
816dba6 to
38952d5
Compare
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — This is a 138-file cross-cutting Effect tracing and lint-enforcement refactor that changes observability and execution wrappers across production paths, including authentication code. The authentication-path changes and remaining tracing-boundary concerns require targeted human review. You can add or adjust custom eligibility rules. Learn more. |
38952d5 to
8bf9cdc
Compare
b9fc278 to
711b7e8
Compare
b9fc278 to
711b7e8
Compare
38952d5 to
8bf9cdc
Compare
711b7e8 to
49c603b
Compare
d8c7047 to
b4f03cf
Compare
87df307 to
92d4233
Compare
| Effect.withSpan("environment.authorization.http"), | ||
| withRelayClientTracing, | ||
| ), | ||
| authorizeDpop: Effect.fn("RemoteEnvironmentAuthorization.authorizeDpop")(function (input) { |
There was a problem hiding this comment.
Both operations already have explicit environment.authorization* spans, so these named wrappers add redundant spans around the existing tracing boundaries. Please keep the existing span names/options and use unnamed Effect.fn wrappers for both operations.
| authorizeDpop: Effect.fn("RemoteEnvironmentAuthorization.authorizeDpop")(function (input) { | |
| authorizeDpop: Effect.fn(function (input) { |
Posted via Macroscope — Effect Service Conventions
| probeDistros, | ||
| preWarm: (distro) => | ||
| provideSpawner(preWarmImpl(distro)).pipe(Effect.withSpan("desktop.wsl.preWarm")), | ||
| preWarm: Effect.fn("DesktopWslEnvironment.preWarm")(function (distro) { |
There was a problem hiding this comment.
These production WSL operations already use explicit desktop.wsl.* spans. The named wrappers add a second operation span to preWarm, prepareRuntime, pruneRuntimes, invalidateRuntime, probeRuntime, and ensureNodePty. Please keep the existing span names and use unnamed wrappers for these operations.
| preWarm: Effect.fn("DesktopWslEnvironment.preWarm")(function (distro) { | |
| preWarm: Effect.fn(function (distro) { |
Posted via Macroscope — Effect Service Conventions
| return EnvironmentAuth.of({ | ||
| getDescriptor: () => | ||
| Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuth.getDescriptor")), | ||
| getDescriptor: Effect.fn("EnvironmentAuth.getDescriptor")(function () { |
There was a problem hiding this comment.
getDescriptor already uses Effect.withSpan("EnvironmentAuth.getDescriptor"); this named wrapper creates a second span with the same name. Please use an unnamed wrapper to retain the existing single tracing boundary.
| getDescriptor: Effect.fn("EnvironmentAuth.getDescriptor")(function () { | |
| getDescriptor: Effect.fn(function () { |
Posted via Macroscope — Effect Service Conventions
| return EnvironmentAuthPolicy.of({ | ||
| getDescriptor: () => | ||
| Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")), | ||
| getDescriptor: Effect.fn("EnvironmentAuthPolicy.getDescriptor")(function () { |
There was a problem hiding this comment.
getDescriptor already has a withSpan with this exact name. The named Effect.fn adds an identical outer span; please use the unnamed wrapper and preserve the existing span.
| getDescriptor: Effect.fn("EnvironmentAuthPolicy.getDescriptor")(function () { | |
| getDescriptor: Effect.fn(function () { |
Posted via Macroscope — Effect Service Conventions
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the
Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Desktop services and settings apps/desktop/src/app/*, apps/desktop/src/backend/*, apps/desktop/src/electron/*, apps/desktop/src/settings/*, apps/desktop/src/snapShot/*, apps/desktop/src/ssh/*, apps/desktop/src/updates/*, apps/desktop/src/wsl/* |
Desktop operations now use named or untraced Effect wrappers. Production settings setters annotate spans with input attributes. A test checks the main-window-bounds span and its attributes. |
Server services and request handlers apps/server/scripts/*, apps/server/src/auth/*, apps/server/src/cloud/*, apps/server/src/device/*, apps/server/src/environment/*, apps/server/src/git/*, apps/server/src/htmlRender/*, apps/server/src/mcp/* |
Callbacks use Effect wrappers. The orchestration executor also uses Effect.catchIf for a specific interrupt-failure condition. |
Orchestration services and state apps/server/src/orchestration-v2/* |
Orchestration services, stores, adapters, and test helpers use Effect wrappers. The private daemon layer and provider-adapter layer are removed. |
Server data, provider, and preview operations apps/server/src/persistence/*, apps/server/src/preview/*, apps/server/src/process/*, apps/server/src/project/*, apps/server/src/provider/*, apps/server/src/pullRequest/*, apps/server/src/relay/*, apps/server/src/resourceTelemetry/*, apps/server/src/sourceControl/*, apps/server/src/telemetry/*, apps/server/src/textGeneration/*, apps/server/src/vcs/* |
Service and callback implementations use named or untraced Effect wrappers. Existing storage, forwarding, and preview behavior is retained. |
Client runtime and protocol operations apps/web/src/connection/*, packages/client-runtime/src/*, packages/effect-acp/src/*, packages/effect-codex-app-server/src/* |
Client state, connection, authorization, web storage, and protocol callbacks use Effect wrappers. Handler-registration and message-processing behavior remain unchanged. |
Provider services and adapters packages/provider-acp-registry/src/*, packages/provider-acp/src/*, packages/provider-core/src/*, packages/provider-cursor/src/*, packages/provider-muse/src/*, packages/provider-opencode/src/*, packages/provider-pi/src/*, packages/provider-testing/src/* |
Provider services and adapter operations use Effect wrappers. Their described capability results, delegation, and provider-session behavior remain unchanged. |
Source-control provider operations packages/source-control-azure-devops/src/*, packages/source-control-bitbucket/src/*, packages/source-control-forgejo/src/*, packages/source-control-gitcafe/src/*, packages/source-control-github/src/*, packages/source-control-gitlab/src/* |
Provider operations use named Effect wrappers. Bitbucket revision-cache keys now use a schema-based encoder. |
Infrastructure and shared utilities infra/relay/src/*, infra/task-cache/src/*, packages/shared/src/*, packages/ssh/src/*, tsconfig.base.json |
Infrastructure and shared callbacks use Effect wrappers. The base configuration changes the Effect function diagnostic severity from suggestion to error. |
Priority:
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Refactor
Suggested reviewers: maria-rcks, t3dotgg
Merge Risk: 
Minimal · up to 98adf
-
The reviewed forwarding changes have no identified merge-blocking issue; proceed with normal checks.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description explains the problem, implementation, scope, tracing behavior, and focused validation results. It is complete enough for review, although it does not explicitly link a triaged issue or maintainer approval.
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4: unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions, the
agent CLI test keeps row 21's queue and fork case beside this row's cases,
and long comments are cut to the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nciliation With T3CODE_LAZURIO_FOLDER a hosted Environment's Chat starts in its Lazurio Folder: decorators over the services orchestration-v2/runtimeLayer.ts builds keep projects, commands and agent sessions in the Folder and offer no Scratch, the startup adopts or creates the Folder's project through ProjectService, and `t3 lazurio model` writes the Platform's recommended model as the Folder project's own override. The web leaves "Add project" and "Copy prompt link" out when every Environment is managed. On v0.1.3 every upstream seam merges cleanly: useHandleNewThread moved into createNewThreadHandler (pingdotgg#25366) and the managedNewThread seam moved with it; runtimeLayer gained GuestShareService and PreviewAgentActivity (pingdotgg#24104, pingdotgg#25184) without touching the guards. useHandleNewThread.test.ts keeps both upstream's offline-machine block (pingdotgg#23967) and the overlay's managed-entry block. For the new lint rules (pingdotgg#21514, pingdotgg#25099) the overlay's long comments are cut to four lines, a bare issue number is dropped, and the guard decorators use Effect.fn("LazurioManagedFolder.<op>") like the existing update guard. This also adds lazurioFolder to ServerConfig, which row 6's prompt draft reads. On v0.1.4: Sidebar.tsx keeps upstream's sidebar tree and delegated-thread hooks next to the managed-Folder hook. ProjectService.listPage (new upstream) is read-only and stays unguarded. Upstream's fallback model (packages/shared/src/usageLimits.ts) applies only when fallbackModelSelection is set, which defaults to null, and the default provider's usage window is used up; t3_thread_launch keeps it under that condition, as upstream's own launches do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions (now
t3code/no-unreasoned-state-sync), the
agent CLI test keeps row 21's queue and fork case beside this row's cases,
and long comments are cut to the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions (now
t3code/no-unreasoned-state-sync), the
agent CLI test keeps row 21's queue and fork case beside this row's cases,
and long comments are cut to the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions (now
t3code/no-unreasoned-state-sync), the
agent CLI test keeps row 21's queue and fork case beside this row's cases,
and long comments are cut to the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nciliation With T3CODE_LAZURIO_FOLDER a hosted Environment's Chat starts in its Lazurio Folder: decorators over the services orchestration-v2/runtimeLayer.ts builds keep projects, commands and agent sessions in the Folder and offer no Scratch, the startup adopts or creates the Folder's project through ProjectService, and `t3 lazurio model` writes the Platform's recommended model as the Folder project's own override. The web leaves "Add project" and "Copy prompt link" out when every Environment is managed. On v0.1.3 every upstream seam merges cleanly: useHandleNewThread moved into createNewThreadHandler (pingdotgg#25366) and the managedNewThread seam moved with it; runtimeLayer gained GuestShareService and PreviewAgentActivity (pingdotgg#24104, upstream's offline-machine block (pingdotgg#23967) and the overlay's managed-entry block. For the new lint rules (pingdotgg#21514, pingdotgg#25099) the overlay's long comments are cut to four lines, a bare issue number is dropped, and the guard decorators use Effect.fn("LazurioManagedFolder.<op>") like the existing update guard. This also adds lazurioFolder to ServerConfig, which row 6's prompt draft reads. On v0.1.4: Sidebar.tsx keeps upstream's sidebar tree and delegated-thread hooks next to the managed-Folder hook. ProjectService.listPage (new upstream) is read-only and stays unguarded. Upstream's fallback model (packages/shared/src/usageLimits.ts) applies only when fallbackModelSelection is set, which defaults to null, and the default provider's usage window is used up; t3_thread_launch keeps it under that condition, as upstream's own launches do. On v0.1.5 upstream adds "Turn into project" (pingdotgg#26767). runtimeLayer.ts gives ScratchThreadPromotion the guarded project service and guardScratch's project folders, so on a managed Environment promote fails closed (no Scratch root, no Scratch project; covered in managedFolderGuards.test.ts), and the web offers no action because the server sends no scratchWorkspaceRoot. The imports in runtimeLayer.ts and ws.ts keep both sides. Hiding GitActionsControl's git part for the Folder holds with the new showActions (pingdotgg#26904). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so agentCliRequestScope, which nothing imports, is module-private. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions
(now t3code/no-unreasoned-state-sync), the agent CLI test keeps row 21's
queue and fork case beside this row's cases, and long comments are cut to
the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so
ACTING_SENDER_NAME_MAX_LENGTH, ClientSurfaceActingSender,
actingSenders.ts's make and ACTING_SENDERS_ROUTE, which nothing imports,
are module-private. actingSenderVisibility.ts must stay the same file on
the server and in the web, and each side uses part of it, so its
functions keep their exports and are @public to knip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nciliation With T3CODE_LAZURIO_FOLDER a hosted Environment's Chat starts in its Lazurio Folder: decorators over the services orchestration-v2/runtimeLayer.ts builds keep projects, commands and agent sessions in the Folder and offer no Scratch, the startup adopts or creates the Folder's project through ProjectService, and `t3 lazurio model` writes the Platform's recommended model as the Folder project's own override. The web leaves "Add project" and "Copy prompt link" out when every Environment is managed. On v0.1.3 every upstream seam merges cleanly: useHandleNewThread moved into createNewThreadHandler (pingdotgg#25366) and the managedNewThread seam moved with it; runtimeLayer gained GuestShareService and PreviewAgentActivity (pingdotgg#24104, upstream's offline-machine block (pingdotgg#23967) and the overlay's managed-entry block. For the new lint rules (pingdotgg#21514, pingdotgg#25099) the overlay's long comments are cut to four lines, a bare issue number is dropped, and the guard decorators use Effect.fn("LazurioManagedFolder.<op>") like the existing update guard. This also adds lazurioFolder to ServerConfig, which row 6's prompt draft reads. On v0.1.4: Sidebar.tsx keeps upstream's sidebar tree and delegated-thread hooks next to the managed-Folder hook. ProjectService.listPage (new upstream) is read-only and stays unguarded. Upstream's fallback model (packages/shared/src/usageLimits.ts) applies only when fallbackModelSelection is set, which defaults to null, and the default provider's usage window is used up; t3_thread_launch keeps it under that condition, as upstream's own launches do. On v0.1.5 upstream adds "Turn into project" (pingdotgg#26767). runtimeLayer.ts gives ScratchThreadPromotion the guarded project service and guardScratch's project folders, so on a managed Environment promote fails closed (no Scratch root, no Scratch project; covered in managedFolderGuards.test.ts), and the web offers no action because the server sends no scratchWorkspaceRoot. The imports in runtimeLayer.ts and ws.ts keep both sides. Hiding GitActionsControl's git part for the Folder holds with the new showActions (pingdotgg#26904). On v0.1.6 upstream adds pinning and archiving projects (pingdotgg#26154) and mutateProjectWithClone (pingdotgg#24915); the overlay keeps its managedFolder import beside it in ws.ts, and the command palette's Add project keeps the overlay's condition under upstream's new name, addProjectAction. guardProjects refuses archiving the Folder's project: archived, a new chat from the sidebar would lead to a palette whose one choice, Add project, a managed Environment refuses. Pinning it and archiving earlier projects stay allowed. The app on a managed Environment also triages nothing (#147): triage clones and compares upstream's source without the overlay, and since v0.1.6 drafts an issue there with the Environment's diagnosis (pingdotgg#24955). The descriptor no longer offers capabilities.triage there (beside serverBrowser), and guardTriage, where server.ts builds upstream's TriageService, refuses prepare. The t3 triage command stays upstream's, as on v0.1.3: a person runs it in a terminal whose environment does not carry the Folder, and it asks before it files anything. Side chats (pingdotgg#26901) are thread.fork with sideChat, which guardCommands already keeps in the Folder's root. Resolving the config logs when it removes expired attachment uploads (config.ts, as on v0.1.3), and the line reached stdout before the JSON the Platform parses. postToRunningService now resolves with upstream's new quietLogs (pingdotgg#27817), as t3 auth --json does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. On v0.1.6 upstream's provider dialog imports useSecretSources for a local ACP agent's variables (pingdotgg#27115) beside the overlay's LazurioSignInChoice; secret sources stay off in Lazurio's build (T3CODE_FEATURE_SECRETS is not set). Codex's new "Use existing CLI" (pingdotgg#23160) sits in ManagedCodexSetup, which a Lazurio Environment replaces with LazurioSignInRow. Upstream's ChatGPT handoff (unchanged since v0.1.3) ran a ChatGPT sign-in outside this guard (#145): a client asks the server on its own device, its primary Environment, to sign in in memory and hand the account to another Environment's instance. A Lazurio Environment now runs none: ws.ts passes chatGptHandoffSubscribe through handoff, which fails with LAZURIO_CHATGPT_HANDOFF whenever T3CODE_LAZURIO_FOLDER is set, whatever the instance, because the server cannot tell a peer's Codex from another provider. The guard also refuses reconnectProfile, the export that only feeds a handoff, for a Lazurio Environment's Codex; it reads only T3's own store, which there holds at most an account from before the guard, one the person can only disconnect. The web does not start a handoff through a Lazurio primary (runsChatGptHandoff in readSignInRouting), so the target signs in itself, as it does with no primary connected. The Launchpad parses `t3 lazurio providers` as it parses the model command, and both post through row 15's postToRunningService, which resolves the config with quietLogs; the test covers both commands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so agentCliRequestScope, which nothing imports, is module-private. On v0.1.6 upstream's projects carry pinnedAt and archivedAt (pingdotgg#26154), so the Buddy thread test's project sets both to null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions
(now t3code/no-unreasoned-state-sync), the agent CLI test keeps row 21's
queue and fork case beside this row's cases, and long comments are cut to
the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so
ACTING_SENDER_NAME_MAX_LENGTH, ClientSurfaceActingSender,
actingSenders.ts's make and ACTING_SENDERS_ROUTE, which nothing imports,
are module-private. actingSenderVisibility.ts must stay the same file on
the server and in the web, and each side uses part of it, so its
functions keep their exports and are @public to knip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nciliation With T3CODE_LAZURIO_FOLDER a hosted Environment's Chat starts in its Lazurio Folder: decorators over the services orchestration-v2/runtimeLayer.ts builds keep projects, commands and agent sessions in the Folder and offer no Scratch, the startup adopts or creates the Folder's project through ProjectService, and `t3 lazurio model` writes the Platform's recommended model as the Folder project's own override. The web leaves "Add project" and "Copy prompt link" out when every Environment is managed. On v0.1.3 every upstream seam merges cleanly: useHandleNewThread moved into createNewThreadHandler (pingdotgg#25366) and the managedNewThread seam moved with it; runtimeLayer gained GuestShareService and PreviewAgentActivity (pingdotgg#24104, upstream's offline-machine block (pingdotgg#23967) and the overlay's managed-entry block. For the new lint rules (pingdotgg#21514, pingdotgg#25099) the overlay's long comments are cut to four lines, a bare issue number is dropped, and the guard decorators use Effect.fn("LazurioManagedFolder.<op>") like the existing update guard. This also adds lazurioFolder to ServerConfig, which row 6's prompt draft reads. On v0.1.4: Sidebar.tsx keeps upstream's sidebar tree and delegated-thread hooks next to the managed-Folder hook. ProjectService.listPage (new upstream) is read-only and stays unguarded. Upstream's fallback model (packages/shared/src/usageLimits.ts) applies only when fallbackModelSelection is set, which defaults to null, and the default provider's usage window is used up; t3_thread_launch keeps it under that condition, as upstream's own launches do. On v0.1.5 upstream adds "Turn into project" (pingdotgg#26767). runtimeLayer.ts gives ScratchThreadPromotion the guarded project service and guardScratch's project folders, so on a managed Environment promote fails closed (no Scratch root, no Scratch project; covered in managedFolderGuards.test.ts), and the web offers no action because the server sends no scratchWorkspaceRoot. The imports in runtimeLayer.ts and ws.ts keep both sides. Hiding GitActionsControl's git part for the Folder holds with the new showActions (pingdotgg#26904). On v0.1.6 upstream adds pinning and archiving projects (pingdotgg#26154) and mutateProjectWithClone (pingdotgg#24915); the overlay keeps its managedFolder import beside it in ws.ts, and the command palette's Add project keeps the overlay's condition under upstream's new name, addProjectAction. guardProjects refuses archiving the Folder's project: archived, a new chat from the sidebar would lead to a palette whose one choice, Add project, a managed Environment refuses. Pinning it and archiving earlier projects stay allowed. The app on a managed Environment also triages nothing (#147): triage clones and compares upstream's source without the overlay, and since v0.1.6 drafts an issue there with the Environment's diagnosis (pingdotgg#24955). The descriptor no longer offers capabilities.triage there (beside serverBrowser), and guardTriage, where server.ts builds upstream's TriageService, refuses prepare. The t3 triage command stays upstream's, as on v0.1.3: a person runs it in a terminal whose environment does not carry the Folder, and it asks before it files anything. Side chats (pingdotgg#26901) are thread.fork with sideChat, which guardCommands already keeps in the Folder's root. Resolving the config logs when it removes expired attachment uploads (config.ts, as on v0.1.3), and the line reached stdout before the JSON the Platform parses. postToRunningService now resolves with upstream's new quietLogs (pingdotgg#27817), as t3 auth --json does. On v0.1.7 the Environment descriptor gained oneTimeSchedules beside the triage capability the overlay keeps off a Lazurio Environment, and AnalyticsService reads the managed policy beside the guarded triage layer. The settings writer now takes the client's patch for the managed policy (pingdotgg#27197); the overlay's updateSettingsWith has none and passes {}, so the policy still vets what the change does and refuses it at a locked setting, which a new test shows. Effect 4.1.2 moved SecureRandom out of NodeServices: the Folder project's id comes from SecureRandom, and the tests provide NodeCrypto and the test managed policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. On v0.1.6 upstream's provider dialog imports useSecretSources for a local ACP agent's variables (pingdotgg#27115) beside the overlay's LazurioSignInChoice; secret sources stay off in Lazurio's build (T3CODE_FEATURE_SECRETS is not set). Codex's new "Use existing CLI" (pingdotgg#23160) sits in ManagedCodexSetup, which a Lazurio Environment replaces with LazurioSignInRow. Upstream's ChatGPT handoff (unchanged since v0.1.3) ran a ChatGPT sign-in outside this guard (#145): a client asks the server on its own device, its primary Environment, to sign in in memory and hand the account to another Environment's instance. A Lazurio Environment now runs none: ws.ts passes chatGptHandoffSubscribe through handoff, which fails with LAZURIO_CHATGPT_HANDOFF whenever T3CODE_LAZURIO_FOLDER is set, whatever the instance, because the server cannot tell a peer's Codex from another provider. The guard also refuses reconnectProfile, the export that only feeds a handoff, for a Lazurio Environment's Codex; it reads only T3's own store, which there holds at most an account from before the guard, one the person can only disconnect. The web does not start a handoff through a Lazurio primary (runsChatGptHandoff in readSignInRouting), so the target signs in itself, as it does with no primary connected. The Launchpad parses `t3 lazurio providers` as it parses the model command, and both post through row 15's postToRunningService, which resolves the config with quietLogs; the test covers both commands. On v0.1.7: upstream's managed policy can lock Codex's setupMode, which hides the ChatGPT button and denies ChatGPT's own runtime. The lock pins Codex to setupMode "existing", the host's own CLI (PIN_BYPASS_FIELDS in managedProviders.ts), so it rules out only T3's managed runtime, not the CLI sign-in Getting started does. In Add provider the lock therefore hides only upstream's ChatGPT button, and the overlay's sign-in choice around it still links to Getting started, which a browser test shows under the lock. A Codex instance's settings row keeps Lazurio's row, which offers Getting started under that lock too; CodexSetupSection reads the policy before its Lazurio early return so the hook order stays the same. The overlay's provider turn-on goes through updateSettingsWith, which the managed policy vets. Tests provide ManagedPolicy.layerTest() and NodeCrypto, since Effect 4.1.2 moved SecureRandom out of NodeServices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so agentCliRequestScope, which nothing imports, is module-private. On v0.1.6 upstream's projects carry pinnedAt and archivedAt (pingdotgg#26154), so the Buddy thread test's project sets both to null. On v0.1.7 effect/Crypto is gone: the send key hashes with effect/crypto/Digest (sha256), and the Buddy surface testkit provides NodeCrypto beside NodeServices. Upstream renamed the MCP client's webOrigin to hostedAppUrl, so the agent commands' scope strips hostedAppUrl to keep their thread links `t3-thread://`; any other MCP client keeps the hosted app link McpOAuth sets. The CLI test checks that link against McpOAuth's own value, so a rewrite of it fails the test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions
(now t3code/no-unreasoned-state-sync), the agent CLI test keeps row 21's
queue and fork case beside this row's cases, and long comments are cut to
the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so
ACTING_SENDER_NAME_MAX_LENGTH, ClientSurfaceActingSender,
actingSenders.ts's make and ACTING_SENDERS_ROUTE, which nothing imports,
are module-private. actingSenderVisibility.ts must stay the same file on
the server and in the web, and each side uses part of it, so its
functions keep their exports and are @public to knip.
On v0.1.7: upstream renamed the MCP caller's `webOrigin` to
`hostedAppUrl` and sets it in the OAuth authenticator for every client
that is not a peer link. The acting sender rides beside it unchanged. The
auth tests provide `ManagedPolicy.layerTest()`, which `EnvironmentAuth`
now needs, and `NodeCrypto.layer`, which Effect 4.1.2 no longer brings
with `NodeServices.layer`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. On v0.1.6 upstream's provider dialog imports useSecretSources for a local ACP agent's variables (pingdotgg#27115) beside the overlay's LazurioSignInChoice; secret sources stay off in Lazurio's build (T3CODE_FEATURE_SECRETS is not set). Codex's new "Use existing CLI" (pingdotgg#23160) sits in ManagedCodexSetup, which a Lazurio Environment replaces with LazurioSignInRow. Upstream's ChatGPT handoff (unchanged since v0.1.3) ran a ChatGPT sign-in outside this guard (#145): a client asks the server on its own device, its primary Environment, to sign in in memory and hand the account to another Environment's instance. A Lazurio Environment now runs none: ws.ts passes chatGptHandoffSubscribe through handoff, which fails with LAZURIO_CHATGPT_HANDOFF whenever T3CODE_LAZURIO_FOLDER is set, whatever the instance, because the server cannot tell a peer's Codex from another provider. The guard also refuses reconnectProfile, the export that only feeds a handoff, for a Lazurio Environment's Codex; it reads only T3's own store, which there holds at most an account from before the guard, one the person can only disconnect. The web does not start a handoff through a Lazurio primary (runsChatGptHandoff in readSignInRouting), so the target signs in itself, as it does with no primary connected. The Launchpad parses `t3 lazurio providers` as it parses the model command, and both post through row 15's postToRunningService, which resolves the config with quietLogs; the test covers both commands. On v0.1.7: upstream's managed policy can lock Codex's setupMode, which hides the ChatGPT button and denies ChatGPT's own runtime. The lock pins Codex to setupMode "existing", the host's own CLI (PIN_BYPASS_FIELDS in managedProviders.ts), so it rules out only T3's managed runtime, not the CLI sign-in Getting started does. In Add provider the lock therefore hides only upstream's ChatGPT button, and the overlay's sign-in choice around it still links to Getting started. A browser test shows the link under the lock, and that the dialog hands the choice upstream's button only without it; the test fails if the lock check in AddProviderInstanceDialog.tsx goes. A Codex instance's settings row keeps Lazurio's row, which offers Getting started under that lock too; CodexSetupSection reads the policy before its Lazurio early return so the hook order stays the same. The overlay's provider turn-on goes through updateSettingsWith, which the managed policy vets. Tests provide ManagedPolicy.layerTest() and NodeCrypto, since Effect 4.1.2 moved SecureRandom out of NodeServices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so agentCliRequestScope, which nothing imports, is module-private. On v0.1.6 upstream's projects carry pinnedAt and archivedAt (pingdotgg#26154), so the Buddy thread test's project sets both to null. On v0.1.7 effect/Crypto is gone: the send key hashes with effect/crypto/Digest (sha256), and the Buddy surface testkit provides NodeCrypto beside NodeServices. Upstream renamed the MCP client's webOrigin to hostedAppUrl, so the agent commands' scope strips hostedAppUrl to keep their thread links `t3-thread://`; any other MCP client keeps the hosted app link McpOAuth sets. The CLI test checks that link against McpOAuth's own value, so a rewrite of it fails the test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions
(now t3code/no-unreasoned-state-sync), the agent CLI test keeps row 21's
queue and fork case beside this row's cases, and long comments are cut to
the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so
ACTING_SENDER_NAME_MAX_LENGTH, ClientSurfaceActingSender,
actingSenders.ts's make and ACTING_SENDERS_ROUTE, which nothing imports,
are module-private. actingSenderVisibility.ts must stay the same file on
the server and in the web, and each side uses part of it, so its
functions keep their exports and are @public to knip.
On v0.1.7: upstream renamed the MCP caller's `webOrigin` to
`hostedAppUrl` and sets it in the OAuth authenticator for every client
that is not a peer link. The acting sender rides beside it unchanged. The
auth tests provide `ManagedPolicy.layerTest()`, which `EnvironmentAuth`
now needs, and `NodeCrypto.layer`, which Effect 4.1.2 no longer brings
with `NodeServices.layer`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nciliation With T3CODE_LAZURIO_FOLDER a hosted Environment's Chat starts in its Lazurio Folder: decorators over the services orchestration-v2/runtimeLayer.ts builds keep projects, commands and agent sessions in the Folder and offer no Scratch, the startup adopts or creates the Folder's project through ProjectService, and `t3 lazurio model` writes the Platform's recommended model as the Folder project's own override. The web leaves "Add project" and "Copy prompt link" out when every Environment is managed. On v0.1.3 every upstream seam merges cleanly: useHandleNewThread moved into createNewThreadHandler (pingdotgg#25366) and the managedNewThread seam moved with it; runtimeLayer gained GuestShareService and PreviewAgentActivity (pingdotgg#24104, upstream's offline-machine block (pingdotgg#23967) and the overlay's managed-entry block. For the new lint rules (pingdotgg#21514, pingdotgg#25099) the overlay's long comments are cut to four lines, a bare issue number is dropped, and the guard decorators use Effect.fn("LazurioManagedFolder.<op>") like the existing update guard. This also adds lazurioFolder to ServerConfig, which row 6's prompt draft reads. On v0.1.4: Sidebar.tsx keeps upstream's sidebar tree and delegated-thread hooks next to the managed-Folder hook. ProjectService.listPage (new upstream) is read-only and stays unguarded. Upstream's fallback model (packages/shared/src/usageLimits.ts) applies only when fallbackModelSelection is set, which defaults to null, and the default provider's usage window is used up; t3_thread_launch keeps it under that condition, as upstream's own launches do. On v0.1.5 upstream adds "Turn into project" (pingdotgg#26767). runtimeLayer.ts gives ScratchThreadPromotion the guarded project service and guardScratch's project folders, so on a managed Environment promote fails closed (no Scratch root, no Scratch project; covered in managedFolderGuards.test.ts), and the web offers no action because the server sends no scratchWorkspaceRoot. The imports in runtimeLayer.ts and ws.ts keep both sides. Hiding GitActionsControl's git part for the Folder holds with the new showActions (pingdotgg#26904). On v0.1.6 upstream adds pinning and archiving projects (pingdotgg#26154) and mutateProjectWithClone (pingdotgg#24915); the overlay keeps its managedFolder import beside it in ws.ts, and the command palette's Add project keeps the overlay's condition under upstream's new name, addProjectAction. guardProjects refuses archiving the Folder's project: archived, a new chat from the sidebar would lead to a palette whose one choice, Add project, a managed Environment refuses. Pinning it and archiving earlier projects stay allowed. The app on a managed Environment also triages nothing (#147): triage clones and compares upstream's source without the overlay, and since v0.1.6 drafts an issue there with the Environment's diagnosis (pingdotgg#24955). The descriptor no longer offers capabilities.triage there (beside serverBrowser), and guardTriage, where server.ts builds upstream's TriageService, refuses prepare. The t3 triage command stays upstream's, as on v0.1.3: a person runs it in a terminal whose environment does not carry the Folder, and it asks before it files anything. Side chats (pingdotgg#26901) are thread.fork with sideChat, which guardCommands already keeps in the Folder's root. Resolving the config logs when it removes expired attachment uploads (config.ts, as on v0.1.3), and the line reached stdout before the JSON the Platform parses. postToRunningService now resolves with upstream's new quietLogs (pingdotgg#27817), as t3 auth --json does. On v0.1.7 the Environment descriptor gained oneTimeSchedules beside the triage capability the overlay keeps off a Lazurio Environment, and AnalyticsService reads the managed policy beside the guarded triage layer. The settings writer now takes the client's patch for the managed policy (pingdotgg#27197); the overlay's updateSettingsWith has none and passes {}, so the policy still vets what the change does and refuses it at a locked setting, which a new test shows. Effect 4.1.2 moved SecureRandom out of NodeServices: the Folder project's id comes from SecureRandom, and the tests provide NodeCrypto and the test managed policy. The live-service test builds auth as EnvironmentAuth.layerRuntime does, but on the same ManagedPolicy.layerTest() its Settings layer reads, as server.ts gives both one policy. layerRuntime reads the host's policy file, so a policy on the machine running the tests could change them; the CLI commands under test still build their own runtime and read the host's policy, as the service does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns them on Root decision 0201, point 4 (#46): with T3CODE_LAZURIO_FOLDER, Codex and Claude sign in with their own CLIs from the Launchpad's Getting started page (T3CODE_LAZURIO_TOOLS_URL). Where the web offered its own "Continue with ChatGPT" it links to that page, the server refuses T3's own Codex sign-in and profile import for every client, and `t3 lazurio providers` turns the providers on and reads their sign-in again at once. On v0.1.3 ProviderAuthService keeps the same methods, and no new way into Codex's own sign-in appeared. CodexSetupSection.tsx moved its logic into CodexSetupSection.logic.ts (pingdotgg#25524); the only conflict was that import beside the overlay's, and both stay. The guard's start and importProfile overrides use Effect.fn for the new effectFnOpportunity diagnostic (pingdotgg#25099), and the overlay's comments are cut to four lines without bare issue numbers (pingdotgg#21514). On v0.1.4 the server and web seams are unchanged. LazurioSignIn's browser test mocks ../state/server by spreading the real module, as upstream's own tests do: its threadTabs import now reaches that module through previewRuntime (row 9's Servers panel), and the partial mock lacked its other exports. On v0.1.6 upstream's provider dialog imports useSecretSources for a local ACP agent's variables (pingdotgg#27115) beside the overlay's LazurioSignInChoice; secret sources stay off in Lazurio's build (T3CODE_FEATURE_SECRETS is not set). Codex's new "Use existing CLI" (pingdotgg#23160) sits in ManagedCodexSetup, which a Lazurio Environment replaces with LazurioSignInRow. Upstream's ChatGPT handoff (unchanged since v0.1.3) ran a ChatGPT sign-in outside this guard (#145): a client asks the server on its own device, its primary Environment, to sign in in memory and hand the account to another Environment's instance. A Lazurio Environment now runs none: ws.ts passes chatGptHandoffSubscribe through handoff, which fails with LAZURIO_CHATGPT_HANDOFF whenever T3CODE_LAZURIO_FOLDER is set, whatever the instance, because the server cannot tell a peer's Codex from another provider. The guard also refuses reconnectProfile, the export that only feeds a handoff, for a Lazurio Environment's Codex; it reads only T3's own store, which there holds at most an account from before the guard, one the person can only disconnect. The web does not start a handoff through a Lazurio primary (runsChatGptHandoff in readSignInRouting), so the target signs in itself, as it does with no primary connected. The Launchpad parses `t3 lazurio providers` as it parses the model command, and both post through row 15's postToRunningService, which resolves the config with quietLogs; the test covers both commands. On v0.1.7: upstream's managed policy can lock Codex's setupMode, which hides the ChatGPT button and denies ChatGPT's own runtime. The lock pins Codex to setupMode "existing", the host's own CLI (PIN_BYPASS_FIELDS in managedProviders.ts), so it rules out only T3's managed runtime, not the CLI sign-in Getting started does. In Add provider the lock therefore hides only upstream's ChatGPT button, and the overlay's sign-in choice around it still links to Getting started. A browser test shows the link under the lock, and that the dialog hands the choice upstream's button only without it; the test fails if the lock check in AddProviderInstanceDialog.tsx goes. A Codex instance's settings row keeps Lazurio's row, which offers Getting started under that lock too; CodexSetupSection reads the policy before its Lazurio early return so the hook order stays the same. The overlay's provider turn-on goes through updateSettingsWith, which the managed policy vets. Tests provide ManagedPolicy.layerTest() and NodeCrypto, since Effect 4.1.2 moved SecureRandom out of NodeServices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds Buddy's thread budíček wakes Buddy with a message into Buddy's T3 thread (root decision 0210, plan DEV-6676) and sends it again after a crash. It needs the send to happen once per wake, to know which thread is Buddy's, and to tell a final refusal from one worth retrying. - `t3 thread send --idempotency-key <key>` passes T3 a SHA-256 digest of the key with the thread and the sender (T3CODE_ACTING_SENDER and T3CODE_ACTING_FOR of the "Buddy za …" trace) as the MCP tool's clientRequestId. T3 derives the command and message ids from it within the MCP client's request namespace. A decorator where server.ts provides the MCP client authenticator puts the agent commands' sessions (label "t3 agent cli") in one namespace, so the same key names the same command across commands, sessions and restarts, and T3's command receipt runs it once. Every other MCP client keeps upstream's namespace. - After a keyed send the command reads what became of it through POST /api/lazurio/agent-cli/send-state (orchestration:read): T3's receipt of the key's command and the message it made. A repeat prints the first send's result with its commandId; the same key with another message fails with `idempotency_conflict` and sends nothing; a key T3 rejected fails with `command_rejected` and stays rejected; a repeat T3 cannot replay because it checks the thread first (archived since) prints `"delivery": "delivered"` with the message's id, run and commandId. The conflict check compares the trimmed text, as T3's tool trims the message it decodes. Other failures keep their codes and are worth sending again with the same key. - `POST /api/lazurio/buddy/thread` finds or makes Buddy's one thread: thread `buddy` on the instance `buddy` in Buddy's project (~/Lazurio/.agents/buddy), made by a fixed command so two first asks make one thread, and brought back if it was archived. A thread `buddy` in another project or on another instance is never taken: the route answers 409 `thread-conflict`. 404 outside Buddy's T3 Code, 409 without Buddy's project. `t3 lazurio buddy thread --json` asks it as an agent command. - `t3 lazurio capabilities` says so with "threadSendIdempotency", "threadSendOutcome" and "buddyThread". The "budíček" label on the message is a claim of the "Buddy za ..." trace and not part of this change. The end-to-end test runs separate `t3 thread send` commands against T3's own MCP tool over the production runtime; with the raw key, without the shared namespace, or without the conflict, rejection or delivered branches, it fails. On v0.1.3 the key keeps its place in row 21's `send`: the key is evaluated first, then the message is sent through `t3_thread_send`, and `--wait` waits only on the run of that send or of the receipt T3 replays. That replaces the rebuilt row 21's `Effect.filterOrElse` around the send. Command ids still come from the MCP client's request namespace and the key (stableCommandId is unchanged), and `t3_thread_send`'s new `link` field (pingdotgg#24784) is ignored by the result schema. The namespace decorator's `authenticate` is an `Effect.fn`, as upstream's McpOAuth.authenticate now is (pingdotgg#25099, effectFnOpportunity is an error), the Buddy test runtime provides upstream's new CodexManagedTokenBroker, and the file headers are cut to the four-line comment limit. On v0.1.4: upstream gives every outside MCP client a web origin for its thread links (pingdotgg#26642); the agent commands' sessions drop it in agentCliRequestScope, so their links stay t3-thread:// links T3 Code's chat opens, as on v0.1.3, and the namespace test asserts both sides. The Buddy test runtime wraps provider hydration with withBuddyInstance as server.ts does (row 23) and provides upstream's new PortDiscovery, and the agent CLI tests provide RemoteDelegation, the peer services and the server settings T3's thread tools now need. On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so agentCliRequestScope, which nothing imports, is module-private. On v0.1.6 upstream's projects carry pinnedAt and archivedAt (pingdotgg#26154), so the Buddy thread test's project sets both to null. On v0.1.7 effect/Crypto is gone: the send key hashes with effect/crypto/Digest (sha256), and the Buddy surface testkit provides NodeCrypto beside NodeServices. Upstream renamed the MCP client's webOrigin to hostedAppUrl, so the agent commands' scope strips hostedAppUrl to keep their thread links `t3-thread://`; any other MCP client keeps the hosted app link McpOAuth sets. The CLI test checks that link against McpOAuth's own value, so a rewrite of it fails the test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r decided a request
Root decision 0210, evening addendum, point 5 (plan DEV-6676, row 27): what
Buddy writes or decides in a thread carries the visible mark „Buddy za <user>“
("Buddy for <user>"). Delegace's wake in Buddy's own thread is not shown at all,
as on Telegram (decided 2026-10-22), so the person sees only Buddy's reply.
Who a session acts as is a claim signed into its token beside the runtime-mode
ceiling (`act`), from a closed set of kinds: buddy with the user's name, or
delegace; budicek is no alias. The agent commands issue their sessions with it
when T3CODE_ACTING_SENDER (with T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE) names one, and refuse any other value before they
read anything. The server reads it from the session alone: an MCP client's
invocation carries it, the client surface runs a dispatch as its session, and a
decorator of the orchestrator records the message or the request's resolution
in a file per thread in the T3 home, only when its own dispatch committed that
step. A replayed command id, an overlapping dispatch of the same id or a retry
takes no one else's step, and a step's first record stands. The web reads
/api/lazurio/acting-senders. The thread's rows leave out Delegace's wake and
hold an agent's message from outside the thread until the answer covers it,
five seconds at most; a server without the route, or an error, shows the thread
at once as upstream does. Buddy's message and a request Buddy decided show
„Buddy za …“. The person's own steps, T3's messages, automations and other
threads' agents get no mark and never wait. Tests: rejections before
successes, the real CLI against /mcp and the client surface through to the
route the web reads, replays on upstream's own orchestrator, the claim in the
token, and the web's label, parse and loader.
On v0.1.3 three small conflicts are resolved by intent. Upstream computes the
folded agent message's sender label once (pingdotgg#24104) and also reads it out in
the accessible heading (pingdotgg#23780); the overlay wraps that senderLabel in
LazurioActingSenderLabel on the visible fold, which is the one place the
mark goes. McpOAuth's authenticate is upstream's Effect.fn now (pingdotgg#25099), and
the client gets the one actingSender spread line there. EnvironmentAuth keeps
row 20's MCP_CLIENT_SUBJECT export. Upstream's guest attribution (pingdotgg#24104)
is a message-context record of its own and does not mark who acted for a
person, so the overlay's session claim stays. The orchestrator decorator's
dispatch is an Effect.fn (effectFnOpportunity), the two effects that ask
the server's record carry justified react-effect-budget suppressions
(now t3code/no-unreasoned-state-sync), the agent CLI test keeps row 21's
queue and fork case beside this row's cases, and long comments are cut to
the four-line limit.
Buddy's day pane counts the messages the timeline shows: the server's day list
(buddySurfaceDays.ts) leaves out Delegace's wake and an agent's message the
record has not answered yet, by the predicate in actingSenderVisibility.ts,
which the server and the web hold as one identical file that the release
contract test keeps equal. A day that opens with a wake jumps to the person's
first message, and a day of wakes alone is not listed.
On v0.1.4: the acting sender sits beside upstream's peer link (pingdotgg#16695) in the session, its signed claims, the MCP client and its caller, next to upstream's narrowed modes and web origin (pingdotgg#16653, pingdotgg#26642); the test takes mcpClientScopes from contracts, where upstream moved it.
On v0.1.5 upstream's pre-commit hook runs knip (pingdotgg#26167), so
ACTING_SENDER_NAME_MAX_LENGTH, ClientSurfaceActingSender,
actingSenders.ts's make and ACTING_SENDERS_ROUTE, which nothing imports,
are module-private. actingSenderVisibility.ts must stay the same file on
the server and in the web, and each side uses part of it, so its
functions keep their exports and are @public to knip.
On v0.1.7: upstream renamed the MCP caller's `webOrigin` to
`hostedAppUrl` and sets it in the OAuth authenticator for every client
that is not a peer link. The acting sender rides beside it unchanged. The
auth tests provide `ManagedPolicy.layerTest()`, which `EnvironmentAuth`
now needs, and `NodeCrypto.layer`, which Effect 4.1.2 no longer brings
with `NodeServices.layer`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enforce
effectFnOpportunityas an error and make reusable Effect-returning functions use explicit function boundaries.Named
Effect.fnremains the default, including synchronous operations and service stubs. Existing span names move into the function wrapper; settings retain argument-derived span attributes. Hot paths, protocol loops, inline match/error handlers, and forwarders over already traced operations use generator-basedEffect.fnUntraced. The relay HTTP authorization span stays inside its tracer override. Provider span names identify their implementation rather than a generic interface.The conversion preserves lazy execution and existing error/cancellation behavior. Statements before a returned Effect now execute with the function's Effect; the runtime-command callers execute that Effect directly. This is a single-rule change rebased onto current main, without the earlier stack's commits.
Validation:
vp run check:changed origin/main: formatting, lint, Knip, GraphQL generation, 34 affected typechecks, and 1,871 tests across 96 files passed.Model: GPT-6.1 Sol, Codex harness. Advisory reviews: Claude Opus 5.5 and Claude Fable 5.1.