# How the Managed Workstream Launcher (`ai-memory run`) Provides Cross-Harness Continuity

> Learn how ai-memory run provides cross-harness continuity by detecting AI harnesses, injecting session flags, and exporting transcripts to a unified workstream store.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: how-to-guide
- Published: 2026-08-19

---

**The managed workstream launcher enables cross-harness continuity by detecting the target AI harness, injecting the correct session flags into the native command line, discovering sessions after launch if necessary, and exporting the resulting transcript into a unified workstream store.**

The `akitaonrails/ai-memory` project treats native sessions from disparate coding agents as interchangeable inputs to a single persistent workstream. By using the managed workstream launcher, a developer can start a task with Claude, resume it with Codex, and review history in Kiro without losing conversational context. This article explains exactly how the launcher coordinates harness detection, session linking, and transcript ingestion according to the source code.

## Harness Identification and Launch Plan Construction

The continuity flow begins inside [`crates/ai-memory-workstream/src/harness.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/harness.rs), where the `ManagedHarness` enum represents every supported agent.

### Selecting the Target Harness

When you invoke `ai-memory run claude` or `ai-memory run kiro-cli`, the CLI parses the first positional argument through `ManagedHarness::from_name`. This maps the string token to a strongly typed variant such as `ManagedHarness::Claude`, `ManagedHarness::KiroV3`, or `ManagedHarness::Codex`. The variant determines every subsequent decision: which flags to inject, where sessions live on disk, and how transcripts are parsed.

### Injecting Session Flags with `build_launch_plan`

Once the harness is known, the launcher calls `build_launch_plan` from [`crates/ai-memory-workstream/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/lib.rs). This function inspects the invocation context and decides whether the launch is **session-bearing** or a **passthrough** utility. For a normal coding session, it injects a native session selector—such as `--session-id`, `--session`, or `--resume`—only when the user has not already supplied one. The function also records the *expected* session ID so the wrapper can associate the child process with the correct workstream later.

For passthrough commands like `codex doctor`, the launch mode is detected as `LaunchMode::Passthrough` and no selector is added, letting the utility run without side effects.

```rust
// Example: launching Claude and linking its session
use ai_memory_workstream::{build_launch_plan, ManagedHarness, LaunchMode};

let harness = ManagedHarness::Claude;
let native_args = vec![OsString::from("--model"), OsString::from("opus")];
let linked_id = Some("a1b2c3d4-5678-90ab-cdef-1234567890ab");

// Build the transparent launch plan; the wrapper injects "--session-id" or "--resume".
let plan = build_launch_plan(harness, None, native_args, linked_id).unwrap();
assert_eq!(plan.mode, LaunchMode::Session);
assert_eq!(plan.args, ["--model", "opus", "--resume", "a1b2c3d4-5678-90ab-cdef-1234567890ab"]);

```

## Native Session Detection and Discovery

Not every harness exposes its session ID before the process starts. The launcher compensates by discovering sessions after the fact and checking for existing sessions before creating new ones.

### Adopting or Creating Sessions

Before spawning a new child, the wrapper checks whether a native session already exists via the `native_session_exists` helper. If an existing session is found, the launcher adopts it and injects the matching resume flag. Otherwise, the launcher generates a fresh UUID (or allows the harness to assign one) and adds the corresponding flag based on the harness type. This design lets a user switch from `ai-memory run codex` to `ai-memory run open-code` without losing conversation history, because the workstream stores a canonical representation of events that is independent of the specific harness.

### Post-Launch Discovery with `discover_native_session`

Some agents—notably **Kiro v3** when the user omits the `--v3` flag—cannot be linked to a session until after they start. In these cases, `discover_native_session` scans the harness-specific session directory, matches the entry against the current working directory, and returns the newly created native session ID. This bridges the gap between launch and linkage.

```rust
// Example: discovering a fresh Kimi session created after a launch
use ai_memory_workstream::{discover_native_session, ManagedHarness};

let home = std::path::Path::new("/home/user/.kimi");
let cwd = std::env::current_dir().unwrap();
let started = std::time::SystemTime::now();

let maybe_id = tokio::runtime::Runtime::new().unwrap().block_on(
    discover_native_session(
        ManagedHarness::Kimi,
        home,
        &cwd,
        None,
        started,
    ),
).unwrap();

if let Some(id) = maybe_id {
    println!("Discovered new Kimi session: {id}");
}

```

## Transcript Export and Unified Workstream Ingestion

After the child process exits, the launcher converts the native transcript into a harness-agnostic event stream that feeds the persistent workstream.

### Parsing Native Stores with `export_transcript`

The `export_transcript` function, defined in [`crates/ai-memory-workstream/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/lib.rs) and implemented via [`crates/ai-memory-workstream/src/transcript.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/transcript.rs), reads the harness's native **JSONL** or **SQLite** store. It converts each record into a `NewWorkstreamEvent` and returns an `ExportedTranscript` that contains a cursor for incremental reads. This cursor is what enables the launcher to resume ingestion on the next invocation without duplicating events.

### Handling Rewritable Journals

Several harnesses—including **Kimi**, **Kiro v3**, and **Grok**—maintain rewritable journals rather than append-only logs. The transcript parser handles these by hashing the consumed prefix, so subsequent exports can detect what has already been ingested and avoid double-counting history.

```rust
// Example: exporting a Kiro v3 transcript after the child exits
use ai_memory_workstream::{
    export_transcript, ManagedHarness, NativeSessionCandidate,
};
use std::path::Path;

let home = Path::new("/home/user/.kiro");
let cwd = std::env::current_dir().unwrap();
let session_dir = None;
let native_session_id = "7f6e5d4c-3b2a-1908-7654-3210fedcba98";

let exported = tokio::runtime::Runtime::new().unwrap().block_on(
    export_transcript(
        ManagedHarness::KiroV3,
        home,
        &cwd,
        session_dir,
        native_session_id,
        None,
    ),
).unwrap();

println!("Exported {} events", exported.events.len());

```

## CLI Orchestration and Process Lifecycle

All of these stages are orchestrated by the binary entry point in [`crates/ai-memory-cli/src/main.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/main.rs). The `ai-memory run` command performs the following sequence:

1. Parses the command-line arguments and resolves the harness via `ManagedHarness::from_name`.
2. Calls `build_launch_plan` to obtain the exact native command line, complete with injected session selectors.
3. Spawns the child process using the wrapper's process-launch utilities.
4. Waits for the child to finish.
5. Invokes `export_transcript` to ingest native events into the workstream store.

This pipeline ensures that every harness writes into the same canonical workstream, making the underlying agent interchangeable while the conversation history remains persistent.

## Summary

- The managed workstream launcher maps each harness to a typed `ManagedHarness` variant in [`harness.rs`](https://github.com/akitaonrails/ai-memory/blob/main/harness.rs).
- `build_launch_plan` injects session selectors only for session-bearing launches, avoiding side effects on passthrough utilities.
- Existing sessions are adopted via `native_session_exists`; missing IDs are discovered post-launch with `discover_native_session`.
- `export_transcript` converts native JSONL or SQLite transcripts into `NewWorkstreamEvent` objects, using a cursor for incremental reads.
- Rewritable journals from Kimi, Kiro v3, and Grok are handled by hashing the consumed prefix to prevent duplicate ingestion.
- The entry point in [`crates/ai-memory-cli/src/main.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/main.rs) ties these steps into a single lifecycle that preserves history across any supported harness.

## Frequently Asked Questions

### What harnesses are supported by the managed workstream launcher?

The launcher supports Claude, Codex, OpenCode, Kiro, Kiro v3, Kimi, Command Code, and Grok, among others. Each variant is defined in [`crates/ai-memory-workstream/src/harness.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/harness.rs) and carries its own session directory, flag conventions, and transcript parser.

### How does `ai-memory run` handle utilities like `codex doctor`?

Commands that do not need a persistent session are detected as `LaunchMode::Passthrough` inside `build_launch_plan`. In this mode, the launcher skips session injection entirely and runs the native binary without modifying its arguments.

### Can I switch from one harness to another without losing history?

Yes. Because the workstream stores a canonical representation of events that is independent of any specific harness, you can start with `ai-memory run codex` and later resume with `ai-memory run claude`. The launcher links each new native session to the existing workstream through the transcript cursor.

### Where is the transcript conversion logic implemented?

The transcript parser lives in [`crates/ai-memory-workstream/src/transcript.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-workstream/src/transcript.rs). It is responsible for reading each harness's native JSONL or SQLite format, converting records into `NewWorkstreamEvent` values, and computing hashes for rewritable journals so that incremental exports remain consistent.