Story
As a person working with the Sidekick in xmd repl, I want it to install middleware that invokes it at selected execution events and can pause execution there, so it can inspect or assist at the moment relevant work happens.
For example, I ask, “Stop when execution reaches Deploy and help me review it.” The Sidekick installs middleware matching that component. When execution reaches the matching boundary, expansion is held and the Sidekick is invoked with the reason and relevant execution context. The person can see what caused the pause, and execution continues from the held point through the agreed continuation action.
A second example is, “When the deploymentPlan binding is added, pause and review it.” The middleware matches publication of that binding in the intended scope, invokes the Sidekick with the newly available information, and holds further expansion at the agreed boundary.
Current gap
#883 establishes an interactive Sidekick that responds to conversation and controls the REPL through host operations. It does not give the Sidekick a way to install execution middleware that calls it back when selected work occurs.
The REPL already has cooperative expansion-pause middleware, and Component.expand surrounds an executable element before resolution and validation. These are useful existing mechanisms. Published component-phase streams are observations that do not delay execution; subscribing to them alone does not establish a stop at a chosen boundary. Binding creation also occurs through several engine paths, so watching changes to the displayed bindings list cannot establish a timely binding-publication trigger.
Accepted direction
- The Sidekick can install middleware selecting execution events at which the host invokes that Sidekick. Reaching a particular component and adding a particular binding are the initial required cases.
- A matching event can suspend further XMD expansion at its defined boundary while the Sidekick handles the event. A report delivered after execution has already passed the requested stop is insufficient.
- The event reaches the owning Sidekick with enough context to identify why it was invoked and which execution, component or binding matched.
- The pause preserves the live continuation. Continuing resumes that work rather than starting a replacement entry or rerunning completed effects.
- Suspension keeps the REPL and Sidekick responsive. It follows the existing distinction between pausing XMD expansion and freezing Effection, external systems or already-started background work.
Decisions before implementation
Prepare an exact installation example and an install → match → pause → Sidekick response → continue walkthrough. Settle the following with the Product Owner before freezing a Planner handoff:
- Installation interface. Define what the Sidekick writes to install, inspect, update and remove middleware. Decide whether it supplies a constrained event rule, an authored middleware component or another supported form. Do not infer arbitrary TypeScript execution or a general plugin loader from the requirement to install middleware.
- Event identity and timing. For components, define name, source-site and scope matching and whether the stop precedes resolution, accepted body execution or another phase. For bindings, define publication versus declaration, first addition versus replacement, durable versus live values, and the supported publication paths. Distinguish same-named bindings in different scopes and define whether an inherited binding counts as newly added.
- Pause extent and continuation. Determine whether a match holds its branch or the entry's whole expansion subtree. Define how the stop is coordinated with existing Pause/Continue and who may resume: the person, Sidekick or both. For a binding trigger, show when the value becomes readable and when downstream expansion is held.
- Invocation and concurrency. Define the event payload and feedback route; repeated or simultaneous matches; one-shot versus persistent registrations; ordering among middleware; and event handling while the Sidekick already has an active turn. Avoid recursive self-invocation and waits in which the paused entry prevents the Sidekick from completing its response.
- Ownership and recovery. Define when installation takes effect, whether it covers a running entry or later entries, and its lifetime across entry settlement, Sidekick cancellation and REPL exit. Settle failed handlers, provider failure and cancellation while held, including an actionable recovery path. Decide separately whether registrations survive a cold reopen; historical inspection does not invoke the Sidekick or activate a live hold.
- Visible behavior. Show installed middleware, the matched event, pausing versus paused state, the Sidekick's response and the available continuation/removal actions. Preserve the existing rule that background activity does not automatically change focus, the selected tab, entry or History position.
These are design decisions rather than delegated implementation choices. The two examples establish the desired capability without choosing a new public middleware syntax.
Architecture boundaries
Compose with existing contextual middleware and the REPL-owned expansion controller. The host owns installation lifetime, dispatch to the Sidekick and live continuation authority; presentation shows their state and returns semantic actions. Retained observations are not themselves authority to pause or resume work.
Respect canonical component dispatch and binding publication. Middleware may observe, hold and delegate at the accepted boundary; it does not fabricate component results, rewrite binding values or bypass entry admission. Identify the actual engine seams for every supported binding path, and propose any missing seam explicitly rather than silently treating one capture operation as all binding creation.
Keep event handling outside the expansion it holds. Teardown unwinds held continuations without releasing cancelled work into ordinary execution. Continuing delegates the suspended operation once. Scope-owned installations disappear with their owner; durable history and live middleware state remain distinct under the agreed recovery design.
Product verification proposal
- Install a component trigger and run an entry with nonmatching work before the target and observable work after it. Show that the target stops at the approved phase, the Sidekick receives the actual event, and later work remains unexpanded until Continue. A notification-only implementation fails this comparison.
- Install a binding trigger, publish the selected binding and let the Sidekick inspect it at the approved stop. Exercise the supported binding-producing paths and a same-named binding in another scope. A display refresh or a trigger that matches only one incidental creation path fails the comparison.
- Continue and observe the same invocation finish once, with no repeated component effects or duplicated durable outcomes.
- Exercise repeated and concurrent matches and a match arriving during an active Sidekick turn. Verify the approved ordering and invocation policy without overlapping turns or deadlock.
- Remove a registration and show a subsequent matching event proceeds without invoking it. Show the approved behavior for registration changes during work and after entry settlement.
- Fail or cancel the Sidekick handler while held, and exit the REPL while held. Demonstrate the agreed recovery, complete teardown and no release of abandoned work. Inspect retained History without calling a provider or reinstalling a live pause.
- While held, use the UI and observe permitted background completion. Show the pause point separately from any advancing Journal head and preserve the user's focus and reading position.
The Architect and Product Owner refine this proposal before the Planner freezes acceptance. The implementation plan names focused integration tests that exercise actual execution boundaries and Sidekick dispatch rather than synthetic event delivery alone.
Relationships and scope
Follow-up to #883 and related to REPL Quest #827. #841 records the retained pause experiment; production pause behavior lives in packages/cli/src/repl/expansion.ts and specs/repl-spec.md. Component expansion and durable/live binding contracts are in specs/executable-mdx-spec.md; keep them and architecture.md aligned with the accepted design.
#896 owns authoring, testing and sharing executable components. If the selected installation interface uses authored middleware components, coordinate that dependency explicitly; ordinary component sharing does not imply execution interception. #894 owns runtime inspection through the Effection inspector and remains independently useful.
Exclude freezing arbitrary Effection tasks or external systems, replacing the scheduler, a general debugger, automatic changes to execution source, and new History fork semantics.
Story
As a person working with the Sidekick in
xmd repl, I want it to install middleware that invokes it at selected execution events and can pause execution there, so it can inspect or assist at the moment relevant work happens.For example, I ask, “Stop when execution reaches
Deployand help me review it.” The Sidekick installs middleware matching that component. When execution reaches the matching boundary, expansion is held and the Sidekick is invoked with the reason and relevant execution context. The person can see what caused the pause, and execution continues from the held point through the agreed continuation action.A second example is, “When the
deploymentPlanbinding is added, pause and review it.” The middleware matches publication of that binding in the intended scope, invokes the Sidekick with the newly available information, and holds further expansion at the agreed boundary.Current gap
#883 establishes an interactive Sidekick that responds to conversation and controls the REPL through host operations. It does not give the Sidekick a way to install execution middleware that calls it back when selected work occurs.
The REPL already has cooperative expansion-pause middleware, and
Component.expandsurrounds an executable element before resolution and validation. These are useful existing mechanisms. Published component-phase streams are observations that do not delay execution; subscribing to them alone does not establish a stop at a chosen boundary. Binding creation also occurs through several engine paths, so watching changes to the displayed bindings list cannot establish a timely binding-publication trigger.Accepted direction
Decisions before implementation
Prepare an exact installation example and an install → match → pause → Sidekick response → continue walkthrough. Settle the following with the Product Owner before freezing a Planner handoff:
These are design decisions rather than delegated implementation choices. The two examples establish the desired capability without choosing a new public middleware syntax.
Architecture boundaries
Compose with existing contextual middleware and the REPL-owned expansion controller. The host owns installation lifetime, dispatch to the Sidekick and live continuation authority; presentation shows their state and returns semantic actions. Retained observations are not themselves authority to pause or resume work.
Respect canonical component dispatch and binding publication. Middleware may observe, hold and delegate at the accepted boundary; it does not fabricate component results, rewrite binding values or bypass entry admission. Identify the actual engine seams for every supported binding path, and propose any missing seam explicitly rather than silently treating one capture operation as all binding creation.
Keep event handling outside the expansion it holds. Teardown unwinds held continuations without releasing cancelled work into ordinary execution. Continuing delegates the suspended operation once. Scope-owned installations disappear with their owner; durable history and live middleware state remain distinct under the agreed recovery design.
Product verification proposal
The Architect and Product Owner refine this proposal before the Planner freezes acceptance. The implementation plan names focused integration tests that exercise actual execution boundaries and Sidekick dispatch rather than synthetic event delivery alone.
Relationships and scope
Follow-up to #883 and related to REPL Quest #827. #841 records the retained pause experiment; production pause behavior lives in
packages/cli/src/repl/expansion.tsandspecs/repl-spec.md. Component expansion and durable/live binding contracts are inspecs/executable-mdx-spec.md; keep them andarchitecture.mdaligned with the accepted design.#896 owns authoring, testing and sharing executable components. If the selected installation interface uses authored middleware components, coordinate that dependency explicitly; ordinary component sharing does not imply execution interception. #894 owns runtime inspection through the Effection inspector and remains independently useful.
Exclude freezing arbitrary Effection tasks or external systems, replacing the scheduler, a general debugger, automatic changes to execution source, and new History fork semantics.