Skip to content

bug: transcript bundle rejects OpenHands and Factory Droid despite platform transcript support #120

Description

@volfiros

Problem

greplica transcript bundle only accepts codex, claude, copilot, and opencode, even though Greplica already supports OpenHands and Factory Droid as install platforms and both platform installers expose transcript projection hooks.

This makes transcript backfill inconsistent across supported platforms. A user can install Greplica for OpenHands or Factory Droid, but cannot use the same transcript bundle workflow to backfill an existing session transcript.

Current behavior

The CLI usage says transcript bundling is limited to four platforms:

greplica transcript bundle --platform codex|claude|copilot|opencode --file <path> [--file <path>...] --out <bundle.md>

The parser enforces the same allowlist in apps/cli/main.ts:

function parseTranscriptBundlePlatform(value: string): InstallPlatform {
  if (value === "codex" || value === "claude" || value === "copilot" || value === "opencode") return value;
  throw new Error(`Invalid --platform ${value}.
${usage("transcriptBundle")}`);
}

But the underlying bundle builder already delegates to the selected platform installer:

const rawTranscript = installer.loadTranscript ? installer.loadTranscript(file) : readFileSync(file, "utf8");
const filteredMarkdown = installer.transcriptToMarkdown(rawTranscript);

That means the command surface is narrower than the platform abstraction underneath it.

Reproduction

From current main, try either supported install platform:

node dist/apps/cli/main.js transcript bundle 
  --platform openhands 
  --file /tmp/some-openhands-events-dir 
  --out /tmp/openhands-bundle.md

Observed:

Invalid --platform openhands.
Usage: main.js transcript bundle --platform codex|claude|copilot|opencode --file <path> [--file <path>...] --out <bundle.md>

Factory Droid fails the same way:

node dist/apps/cli/main.js transcript bundle 
  --platform factory-droid 
  --file /tmp/factory-droid-session.jsonl 
  --out /tmp/factory-droid-bundle.md

Observed:

Invalid --platform factory-droid.

Why this looks supportable

OpenHands already has platform-specific transcript support:

  • libs/install/platforms/openhands.ts implements loadTranscript(eventsDir) for OpenHands event directories.
  • libs/install/platforms/openhands.ts implements transcriptToMarkdown().
  • transcriptPathFromHook() already maps a session id to ~/.openhands/conversations/<conversation-id>/events.

Factory Droid also has transcript support:

  • libs/install/platforms/droid.ts implements sessionSourceRef() / sessionIdFromSourceRef().
  • libs/install/platforms/droid.ts reuses Claude-style JSONL transcript projection via claudeTranscriptToMarkdown().

So the core projection pieces exist. The CLI parser and docs just do not expose them.

OpenHands metadata caveat

OpenHands projection currently emits no metadata, so buildTranscriptBundle() may produce:

session_id: unknown
session_ref: unknown

The content can still be bundled, but the provenance is weaker than other platforms.

A reasonable fix is to derive OpenHands session_id from the event directory path when possible:

~/.openhands/conversations/<conversation-id>/events

Then the bundle can emit:

session_ref: openhands-session:<conversation-id>

If OpenHands events contain an explicit session_id, conversation_id, or similar field, that should win over the path fallback.

Expected behavior

greplica transcript bundle should accept all installed platforms that have a working transcript projection:

greplica transcript bundle --platform openhands --file <events-dir> --out <bundle.md>
greplica transcript bundle --platform factory-droid --file <session.jsonl> --out <bundle.md>

Expected output:

  • OpenHands bundle contains filtered user/agent messages from event-*.json files.
  • Factory Droid bundle contains filtered Claude-style JSONL messages.
  • Session refs are generated when a session id can be derived.
  • Unsupported platforms, such as skills-only integrations without transcript projection, should still be rejected clearly.

Suggested fix direction

  1. Add openhands and factory-droid to parseTranscriptBundlePlatform().
  2. Update the transcript bundle usage text and README/docs.
  3. Add regression coverage in scripts/check-transcript-bundle.js or the Vitest suite if feat:Introduce Vitest testing infrastructure #106 lands first.
  4. For OpenHands, add session metadata extraction so bundle output can include openhands-session:<id> instead of unknown when the event directory shape allows it.

Suggested test cases

  • transcript bundle --platform factory-droid with Claude-style JSONL produces factory-droid-session:<id> and sanitized transcript content.
  • transcript bundle --platform openhands with an events directory containing event-*.json produces sanitized transcript content.
  • OpenHands derives session_id from ~/.openhands/conversations/<id>/events or from event metadata if available.
  • OpenHands still handles missing/unreadable event directories with a clear error or empty transcript behavior consistent with existing platform helpers.

Notes

This is separate from adding new platform support. OpenHands and Factory Droid already exist as install platforms; the bug is that transcript backfill does not expose their existing transcript projection surface.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions