# Advanced Patterns

> Parent context injection, bidirectional communication, and hub activations.

## Parent Context (Cross-Plugin Calls)

When an activation needs to call other activations through the hub, use a generic context type with `OnceLock` for deferred injection:

```rust
#[derive(Clone)]
pub struct MyPlugin<Context> {
    parent: OnceLock<Context>,
}

impl<Context> MyPlugin<Context> {
    pub fn with_context_type(_config: Config) -> Self {
        Self { parent: OnceLock::new() }
    }

    pub fn inject_parent(&self, parent: Context) {
        self.parent.set(parent).ok();
    }
}
```

Then in the builder, use `Arc::new_cyclic` to inject a `Weak<DynamicHub>`:

```rust
let hub = Arc::new_cyclic(|weak_hub: &Weak<DynamicHub>| {
    my_plugin.inject_parent(weak_hub.clone());
    DynamicHub::new("myservice")
        .register(my_plugin)
});
```

**Why `Weak<DynamicHub>`?** Avoids reference cycles. The hub owns the activation via `Arc`, and the activation holds a `Weak` back-reference that won't prevent deallocation.

**Why `Arc::new_cyclic`?** The `Weak` reference must exist before the `Arc` is fully constructed. `Arc::new_cyclic` provides a `Weak` during construction.

## Bidirectional Communication

For methods that need to prompt the client mid-execution (confirmations, prompts, selections):

### Server Side

```rust
use plexus_core::plexus::{wrap_stream_with_bidir, StandardRequest, StandardResponse};

// In your method:
let (ctx, stream) = wrap_stream_with_bidir::<_, StandardRequest, StandardResponse>(
    user_stream,
    "interactive.wizard",
    vec!["interactive".into()],
);
// ctx.request(...) sends a request to the client and awaits response
```

Mark the method schema with `.with_standard_bidirectional()`.

### Client Side (Synapse)

Synapse supports multiple bidirectional modes:

| Mode | Trigger | Behavior |
|------|---------|----------|
| `BidirInteractive` | stdin is TTY | Prompt user via terminal |
| `BidirJson` | stdin is pipe | Output request JSON, read response from stdin |
| `BidirAutoCancel` | non-interactive fallback | Automatically cancel |
| `BidirDefaults` | configured | Use default values from request |
| `BidirCmd <cmd>` | configured | Spawn subprocess per request |
| `BidirRespond` | configured | Print request, agent responds via `synapse <backend> respond` |

## Hub Activations (Nested Routing)

For activations with their own child tree, implement `ChildRouter` and register with `.register_hub()`:

```rust
DynamicHub::new("substrate")
    .register_hub(Solar::new())  // Solar has children like mercury, venus, etc.
```

This enables paths like `substrate.solar.mercury.info`. The hub's schema reports children as `ChildSummary` entries, and Synapse navigates into them via lazy schema fetching.

## Source Paths

| Component | Path |
|-----------|------|
| Bidirectional channels | `plexus-core/src/plexus/bidirectional.rs` |
| Bidir streaming helpers | `plexus-core/src/plexus/streaming.rs` |
| DynamicHub (ChildRouter) | `plexus-core/src/plexus/plexus.rs` |
| Substrate builder (cyclic) | `plexus-substrate/src/builder.rs` |
| Synapse bidir handling | `synapse/src/Synapse/Bidir.hs` |
