Skip to content

ADR-0007: Use the OpenHands Software Agent SDK as Layer 1 (AI Agent Runner)

Status: Accepted — 2026-10-08 Decider: olivier-norture Related: #817 (this discussion), #824 (AI-disclosure follow-up), #815 (README), landscape.md (3-layer model)

Nebuko is organised in three layers (landscape.md): a Layer-1 AI agent runner that executes one individual agent, a Layer-2 workflow engine (this repository), and Layer-3 capabilities (workflows, skills, MCPs). Layer 2 consumes Layer 1 through a narrow call surface; it does not itself implement the agent loop.

The Layer-1 runner must provide, for a single agent invocation:

  • an agent loop that drives the LLM, executes tools and feeds results back;
  • conversation state that survives a multi-turn run and exposes the final response;
  • model-agnostic LLM access so a deployment can point Nebuko at any supported provider without engine changes;
  • system-prompt configuration so the engine can inject skills and the security policy into the system channel.

Building that loop in-house is not product differentiation for Nebuko — it is undifferentiated infrastructure with a large correctness surface (tool dispatch, iteration control, context condensation). The question is which existing runtime to adopt, and whether its license permits the project’s open-source and commercial plans.

Adopt the OpenHands Software Agent SDK (openhands-sdk + openhands-tools, from OpenHands/software-agent-sdk) as the Layer-1 runtime. It is declared as an optional runtime extra in pyproject.toml (kept optional so the engine and its adapters import without pulling the SDK), pinned to a git revision via uv.lock, installed in CI, and wired in src/nebuko/engine/lib/agent_script/features/run_agent/run_agent.py.

Rationale — the features we actually use

Section titled “Rationale — the features we actually use”

The adoption is scoped to a small, verified set of SDK surfaces:

  • Agent + Conversation + arun() — the single-agent run loop; the engine drives one bounded async pass under a watchdog (arun() is the async API).
  • Tool execution loop — include_default_tools selects the built-in tools the engine exposes per role; the SDK owns dispatch and result feedback.
  • Conversation condenser — get_default_condenser(llm=...) keeps a long run within the model window without the engine maintaining its own history compaction.
  • System-prompt configuration — system_prompt_kwargs and security_policy_filename let the engine route skills and the security policy through the system channel instead of appending them to the user message.
  • Model-agnostic LLM access — LLM(**llm_config) over litellm gives one provider-agnostic interface for every configured provider profile.
  • MIT ↔ Apache-2.0 is one-way compatible. The SDK is MIT-licensed (OpenHands/software-agent-sdk); Nebuko is Apache-2.0 (LICENSE). MIT code can be incorporated into an Apache-2.0 project, so the combination is sound.
  • MIT explicitly permits both target uses. MIT grants use, modification, redistribution and commercial exploitation, so an open-source product and a commercial SaaS built on the SDK are both permitted.
  • Obligations are limited to redistribution. MIT requires preserving the copyright notice and license text only when SDK code is redistributed (self-hosted images, vendored copies). Nebuko installs the SDK as a declared dependency; mere dependency use triggers no notice requirement. See the README Acknowledgements section.
  • No output-attribution requirement. MIT says nothing about attributing generated content. The trailing “generated by an AI agent (OpenHands)” line seen on posted comments is a prompt policy of the SDK’s default system prompt (ExternalServicesSection), not a license term. Replacing it is a product/transparency decision tracked separately, not a licensing obligation.
  • Trademark note. MIT grants copyright/patent rights, not trademark rights. Nebuko must not brand itself as “OpenHands” or imply endorsement; referential credit (“uses the OpenHands SDK”) is normal and permitted.
  1. Bespoke in-house agent loop — full control, but re-implements tool dispatch, iteration control and condensation, with no product upside. Higher cost and a larger correctness surface. Rejected.
  2. A different agent framework — viable in principle, but weaker fit for the engine’s skills/system-prompt injection model; adopting it would require re-implementing the prompt routing the engine already relies on. Rejected for now.
  3. OpenHands Cloud / Enterprise — managed commercial offerings. They are a separate product line with their own terms and are not required to run the OSS Layer-1 runtime. Rejected — Nebuko runs the OSS SDK locally on the operator’s runner.
  4. OpenHands Software Agent SDK (chosen) — provides the exact surfaces above, is MIT-licensed, and keeps Layer-1 evolution upstream.
  • Layer-1 capabilities evolve upstream. New tools, condensers and prompt controls arrive without Nebuko maintaining an agent loop.
  • License-safe for OSS and SaaS. The MIT runtime is compatible with the Apache-2.0 project for both open-source distribution and commercial use.
  • Dependency on upstream prompt defaults. SDK-injected prompt text (e.g. the external-services disclosure) is controlled by the engine only through the posting layer / prompt configuration; upstream changes may require engine follow-up. This is accepted and tracked separately.
  • Upgrades are deliberate. The SDK is pinned to a git revision (uv.lock), so version bumps are explicit PRs rather than implicit drift.
  • Narrow coupling. The engine depends on Agent / Conversation / arun(), a few tool-selection knobs, the condenser factory, and the system-prompt/security-policy configuration — a small surface that keeps a future runtime swap feasible.