Skip to content

Epic: Preserve OpenHands UX as an Ouroboros-native AgentOS plugin #42

@shaun0927

Description

@shaun0927

Epic: Assimilate OpenHands as an Ouroboros-native AgentOS capability while preserving the OpenHands user experience

Scope decision

Confirmed target: Full surface.

This epic should treat OpenHands CLI, headless mode, SDK, Local GUI, MCP integration, sandboxing, skills/microagents, event streams, and resume/conversation identity as one end-to-end AgentOS experience. Implementation may still be phased, but the architecture must not optimize only for a CLI wrapper or SDK-only embedding path.

Goal

Make OpenHands run smoothly from Ouroboros as a first-class external agent harness, without reducing OpenHands to a thin command wrapper and without violating the UserLevel plugin boundary defined in #27.

The target outcome is an AgentOS-grade bridge:

  • Users who already know OpenHands should feel that the OpenHands CLI/headless workflow still behaves like OpenHands.
  • Ouroboros should gain a safe, auditable, resumable way to invoke OpenHands and consume its outputs.
  • ooo auto should remain coherent and should not grow OpenHands-specific branching logic.
  • The plugin layer should translate OpenHands runs into Ouroboros-native artifacts: Seeds, handoffs, provenance, audit events, and future Run/Step/Artifact projections.

This epic is intentionally about capability assimilation, not marketplace listing and not vendoring the whole OpenHands platform into this repository.

Background

OpenHands provides a mature AI software-engineering agent stack:

  • OpenHands SDK: composable Python/REST APIs for code-focused agents.
  • OpenHands CLI: terminal experience similar to Codex / Claude Code.
  • Headless mode: scriptable automation with JSONL event output.
  • Local GUI / app server: REST API and browser UI.
  • MCP integration, sandbox support, skills/microagents, security analysis, event streams, and workspace abstraction.

Issue #27 defines the Ouroboros plugin layer as a contract/reference layer, not a marketplace. It also draws a hard line between:

trivial wrapper: run this external command

and:

Ouroboros-native plugin: translate an external capability into an explicit,
permissioned, auditable, resumable, handoff-capable workflow

OpenHands is a strong candidate for this model because it is not merely a CLI; it is an external autonomous agent harness with its own event stream, execution semantics, sandbox choices, and UX expectations.

Non-negotiable product constraint: preserve OpenHands UX

The integration should not make OpenHands feel like a generic subcommand hidden behind Ouroboros.

Preserve, as much as the plugin boundary allows:

  • OpenHands task-driven CLI usage (openhands -t ..., openhands -f ...).
  • OpenHands headless automation semantics (--headless, --json).
  • OpenHands streaming/progress feel when running interactively through Ouroboros.
  • OpenHands configuration expectations, while isolating plugin-owned config where needed.
  • OpenHands MCP awareness and loaded-tool visibility.
  • OpenHands resume/conversation identity where feasible.
  • OpenHands sandbox selection model, but with safer Ouroboros defaults.

Ouroboros should add contract semantics around OpenHands, not flatten the experience into python -m something.

Proposed reference plugin

Initial plugin name:

openhands-agentos

Alternative narrower names if scope is split:

openhands-headless
openhands-handoff
openhands-skills-importer

Recommended first reference slice: openhands-agentos with an initial run + handoff + inspect surface.

Proposed command surface

# Inspect local OpenHands availability and effective config without running an agent.
ooo openhands inspect

# Run OpenHands in a bounded workspace while preserving headless/JSONL semantics.
ooo openhands run \
  --task <task-file-or-inline-task> \
  --workspace <repo-path> \
  --out .omx/artifacts/openhands/<run-id>/events.jsonl

# Convert a captured OpenHands event stream into an Ouroboros handoff.
ooo openhands handoff \
  --run .omx/artifacts/openhands/<run-id>/events.jsonl \
  --out .omx/handoffs/openhands/<run-id>.md

# Summarize an OpenHands run for humans and downstream automation.
ooo openhands summarize --run <events.jsonl>

# Optional later: resume a known OpenHands conversation/run.
ooo openhands resume --run-id <run-id>

The important contract point: ooo openhands run invokes OpenHands only after manifest validation, registry resolution, trust checks, permission checks, risk handling, and audit emission. It is not considered “run by Ouroboros” merely because a subprocess started.

UX preservation requirements

CLI/headless parity

The plugin should pass through the user’s task in a way that maps cleanly to OpenHands native usage:

openhands --headless --json -t "..."

The plugin may wrap this, but it should preserve:

  • task text/file input,
  • JSONL event stream capture,
  • exit status semantics where possible,
  • streaming logs/progress,
  • OpenHands-native error messages when safe,
  • conversation/run identifiers where available.

Interactive experience

If Ouroboros later supports an interactive OpenHands bridge, it should feel like OpenHands inside an Ouroboros session, not like a static batch job. This can be deferred, but the architecture should not block it.

Configuration

The plugin should support two modes:

  1. Isolated mode (default): use plugin-owned config/cache paths to avoid contaminating ~/.openhands and to keep provenance reproducible.
  2. Native mode (explicit opt-in): use the user’s existing OpenHands configuration for maximum fidelity.

The issue should decide whether native mode requires a separate trust scope because it may read existing credentials, MCP configuration, conversation history, or agent settings.

Contract translation

The plugin should translate OpenHands concepts into Ouroboros concepts:

OpenHands concept Ouroboros-native projection
task text / task file Seed input or execution handoff input
headless JSONL events provenance artifact + audit evidence
actions / observations future Run/Step/Artifact events
workspace bounded repo-relative execution target
sandbox provider declared permission/risk boundary
conversation ID resumable plugin state
command execution shell:execute permission usage
file edits filesystem:write permission usage
MCP tools mcp:call capability / external permission evidence
final answer handoff artifact for ooo auto, human review, or harness continuation

Safety and firewall requirements

OpenHands headless mode is powerful. It can execute actions without per-action human confirmation, depending on the mode. Therefore the Ouroboros plugin must provide safety at the outer boundary.

Required safeguards:

  • No default host/process execution if safer sandboxing is available.
  • Workspace must be explicitly bounded.
  • Plugin must refuse ambiguous workspace paths.
  • Plugin must record the exact OpenHands command line and environment-shaping settings, redacting secrets.
  • Plugin must separate OpenHands configuration access from workspace access.
  • Plugin must fail closed if required permissions are not trusted.
  • Plugin must classify OpenHands run as destructive unless the implementation can prove a safer bounded mode.
  • Plugin must not silently pass through arbitrary environment variables.
  • Plugin must not mutate Ouroboros core state except through declared capabilities.
  • Plugin must emit blocked/failure semantics without pretending the external agent ran.

Proposed manifest sketch

{
  "schema_version": "0.1",
  "name": "openhands-agentos",
  "version": "0.1.0",
  "description": "Run OpenHands as an audited external agent harness and convert OpenHands outputs into Ouroboros-native handoff artifacts.",
  "source": {
    "type": "local_path",
    "path": "plugins/openhands-agentos"
  },
  "commands": [
    {
      "namespace": "openhands",
      "name": "inspect",
      "summary": "Inspect local OpenHands availability and effective integration settings.",
      "usage": "ooo openhands inspect",
      "risk": "read_only",
      "requires_confirmation": false
    },
    {
      "namespace": "openhands",
      "name": "run",
      "summary": "Run OpenHands against a bounded workspace and capture JSONL evidence.",
      "usage": "ooo openhands run --task <task> --workspace <path> --out <jsonl-path>",
      "risk": "destructive",
      "requires_confirmation": true
    },
    {
      "namespace": "openhands",
      "name": "handoff",
      "summary": "Convert an OpenHands JSONL run into an Ouroboros handoff artifact.",
      "usage": "ooo openhands handoff --run <jsonl-path> --out <handoff-path>",
      "risk": "write",
      "requires_confirmation": false
    }
  ],
  "capabilities": [
    {
      "name": "ledger",
      "access": "write",
      "reason": "Record invocation, result, and evidence references."
    },
    {
      "name": "provenance",
      "access": "write",
      "reason": "Attach OpenHands event stream and source metadata."
    },
    {
      "name": "handoff",
      "access": "attach",
      "reason": "Attach converted results for downstream Ouroboros execution."
    },
    {
      "name": "state",
      "access": "write",
      "reason": "Persist run IDs and resumable execution metadata."
    }
  ],
  "permissions": [
    {
      "scope": "filesystem:read",
      "risk": "read_only",
      "required": true,
      "reason": "Read task inputs, workspace metadata, and captured OpenHands events."
    },
    {
      "scope": "filesystem:write",
      "risk": "write",
      "required": true,
      "reason": "Write JSONL captures, summaries, state, and handoff artifacts."
    },
    {
      "scope": "shell:execute",
      "risk": "destructive",
      "required": true,
      "reason": "OpenHands may execute commands through its agent runtime."
    },
    {
      "scope": "network:write",
      "risk": "write",
      "required": false,
      "reason": "Optional LLM, MCP, model-provider, or remote sandbox access."
    }
  ],
  "entrypoint": {
    "type": "command",
    "command": "python -m openhands_agentos"
  }
}

This manifest is only a sketch. The implementation must still satisfy the broader #27 contract: safety, auditability, provenance, bounded side effects, and handoff.

Implementation phases

Phase 0 — design spike / feasibility proof

  • Verify the current OpenHands CLI/headless invocation contract.
  • Identify stable JSONL event fields needed for provenance.
  • Identify how OpenHands config paths can be isolated.
  • Identify which sandbox modes are safe enough for a default.
  • Decide whether this plugin should depend on openhands CLI being preinstalled or install its own optional dependency.

Deliverable: short design note under docs/ or plugin README.

Phase 1 — read-only inspection

Implement:

ooo openhands inspect

It should report:

  • OpenHands installed/not installed,
  • version,
  • detected CLI path,
  • detected config mode,
  • available sandbox mode hints,
  • whether JSON headless output appears supported,
  • warnings about unsafe process/host execution.

Risk: read_only.

Phase 2 — JSONL capture without handoff mutation

Implement bounded OpenHands headless execution:

ooo openhands run --task ... --workspace ... --out ...

Required behavior:

  • require explicit trusted shell:execute,
  • require explicit bounded workspace,
  • capture stdout/stderr and JSONL separately where possible,
  • emit audit/provenance metadata,
  • preserve OpenHands exit code semantics,
  • record command line with secret redaction,
  • write run metadata under plugin-owned state.

Risk: likely destructive.

Phase 3 — handoff conversion

Implement:

ooo openhands handoff --run ... --out ...

The handoff should include:

  • task input,
  • OpenHands version and command,
  • workspace path,
  • event summary,
  • file changes inferred from events or git diff,
  • commands executed,
  • errors/failures/blocked actions,
  • final answer,
  • recommended next action for human / ooo auto / test harness,
  • provenance links to raw JSONL and metadata.

Risk: write.

Phase 4 — AgentOS smooth-run loop

Add a higher-level flow that makes OpenHands feel native inside Ouroboros:

ooo openhands agentos --goal <goal> --workspace <repo>

This should coordinate:

  1. goal/task intake,
  2. OpenHands execution,
  3. event capture,
  4. handoff generation,
  5. verification suggestion,
  6. optional downstream ooo auto handoff.

It must not turn ooo auto into an OpenHands-specific router. The plugin owns OpenHands-specific logic.

Phase 5 — optional SDK / GUI / MCP expansion

Only after the CLI/headless bridge is stable:

  • SDK-backed execution path,
  • OpenHands conversation resume integration,
  • MCP configuration projection,
  • Local GUI launch/attach helper,
  • richer event-to-Run/Step/Artifact mapping.

Any manifest/schema expansion must be justified by the reference implementation and should follow #27’s contribution policy.

Acceptance criteria

This epic is complete when:

  • A plugin package exists under plugins/openhands-agentos/ or a scoped external reference repo is documented.
  • The plugin has a valid ouroboros.plugin.json under schema 0.1.
  • The plugin is not a trivial wrapper; it emits audit/provenance/handoff artifacts.
  • ooo openhands inspect works without mutating external systems.
  • ooo openhands run preserves OpenHands headless/JSONL usage semantics as much as possible.
  • ooo openhands run requires explicit trust for dangerous permissions.
  • Workspace paths are bounded and ambiguous paths are rejected.
  • OpenHands config isolation is documented and implemented for the default mode.
  • ooo openhands handoff converts captured OpenHands output into a human-readable and harness-readable Ouroboros handoff.
  • Failure, blocked, cancelled, and completed states are represented explicitly.
  • The implementation records which plugin version, command, arguments, permissions, capabilities, and source evidence were used.
  • The integration preserves the ooo auto boundary: OpenHands-specific behavior remains in the plugin.
  • Tests cover manifest validation, command argument validation, path bounding, handoff conversion, and failure semantics.
  • Documentation explains when this belongs in Q00/ouroboros-plugins as a reference plugin versus a third-party plugin repository.

Open questions

  • Should the first implementation live in this contract/reference repo, or in a separate author repo that follows the SSOT: UserLevel plugin authoring and capability assimilation #27 distribution convention?
  • Should the default mode require Docker/remote sandbox and reject process/host execution?
  • What is the exact trust scope for reading existing ~/.openhands configuration?
  • Should network:write be required or optional for the first version?
  • Should openhands run be split into run-readonly, run-write, and run-destructive modes, or is command-level requires_confirmation sufficient?
  • Which OpenHands JSONL event fields are stable enough to treat as provenance inputs?
  • How should OpenHands conversation resume IDs map to Ouroboros plugin state?

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions