Skip to content

chore(lint): enforce effectFnOpportunity - #25099

Merged
juliusmarminge merged 1 commit into
mainfrom
lint-rules/effectFnOpportunity
Oct 26, 2026
Merged

juliusmarminge merged 1 commit into
mainfrom
lint-rules/effectFnOpportunity

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Enforce effectFnOpportunity as an error and make reusable Effect-returning functions use explicit function boundaries.

Named Effect.fn remains 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-based Effect.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.
  • A tracing regression test verifies exactly one window-bounds operation span, with its input attributes and completed status.
  • Opus 5.5 and Fable 5.1 independently reviewed the revision. Their remaining duplicate forwarding wrappers were converted to untraced generators and checked separately.

Model: GPT-6.1 Sol, Codex harness. Advisory reviews: Claude Opus 5.5 and Claude Fable 5.1.

@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Oct 25, 2026
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 6a7e430 to 1d662e5 Compare October 25, 2026 22:49
@github-actions github-actions Bot added the size:XXL 1,000+ changed lines (additions + deletions). label Oct 25, 2026
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch 2 times, most recently from a19b65b to 09d1eaa Compare October 25, 2026 22:52
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB +7 B (+0.1%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB +7 B (+0.6%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.9 KiB 20.9 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: d171a88 · PR result: 98adf3d · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 09d1eaa to 800f155 Compare October 25, 2026 23:13
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from 5a4b2e3 to 71140aa Compare October 25, 2026 23:13
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 800f155 to 816dba6 Compare October 25, 2026 23:15
@juliusmarminge
juliusmarminge marked this pull request as ready for review October 25, 2026 23:15
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from 3c6d6cd to b9fc278 Compare October 25, 2026 23:18
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 816dba6 to 38952d5 Compare October 25, 2026 23:18
@macroscopeapp

macroscopeapp Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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.

@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 38952d5 to 8bf9cdc Compare October 25, 2026 23:35
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from b9fc278 to 711b7e8 Compare October 25, 2026 23:35
Comment thread apps/desktop/src/app/DesktopWebLinks.ts Resolved
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from b9fc278 to 711b7e8 Compare October 25, 2026 23:37
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch from 38952d5 to 8bf9cdc Compare October 25, 2026 23:37
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from 711b7e8 to 49c603b Compare October 25, 2026 23:54
@juliusmarminge
juliusmarminge force-pushed the lint-rules/effectFnOpportunity branch 3 times, most recently from d8c7047 to b4f03cf Compare October 26, 2026 00:52
@juliusmarminge
juliusmarminge force-pushed the lint-rules/abortControllerInEffect branch from 87df307 to 92d4233 Compare October 26, 2026 03:01
Base automatically changed from lint-rules/abortControllerInEffect to main October 26, 2026 06:02
Effect.withSpan("environment.authorization.http"),
withRelayClientTracing,
),
authorizeDpop: Effect.fn("RemoteEnvironmentAuthorization.authorizeDpop")(function (input) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Suggested change
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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 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.

Suggested change
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 () {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Suggested change
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 () {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Suggested change
getDescriptor: Effect.fn("EnvironmentAuthPolicy.getDescriptor")(function () {
getDescriptor: Effect.fn(function () {

Posted via Macroscope — Effect Service Conventions

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 471cf27 and 98adf3d.

Files selected for processing: 3
  • apps/server/src/provider/ProviderHostLive.ts
  • packages/client-runtime/src/connection/onboarding.ts
  • packages/client-runtime/src/state/pullRequestDiffHttp.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Walkthrough

This pull request migrates Effect callbacks across desktop, server, client, provider, source-control, and infrastructure code to named or untraced Effect functions. It also updates selected handler logic, adds a tracing test, and raises the related TypeScript diagnostic severity.

Changes: Effect function migration

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: Low

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: Passed 4
Check name Status Explanation
Title check Passed The title clearly identifies the primary change: enforcing the effectFnOpportunity lint rule.
Description check Passed 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…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
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.

immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 30, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 31, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 31, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 31, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Oct 31, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 4, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 5, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 5, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 5, 2026
…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>
immakermatty added a commit to Lazurio/t3code that referenced this pull request Nov 5, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant