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)
Context
Section titled “Context”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.
Decision
Section titled “Decision”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_toolsselects 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_kwargsandsecurity_policy_filenamelet 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.
Rationale — licensing
Section titled “Rationale — licensing”- 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.
Alternatives considered
Section titled “Alternatives considered”- 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.
- 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.
- 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.
- OpenHands Software Agent SDK (chosen) — provides the exact surfaces above, is MIT-licensed, and keeps Layer-1 evolution upstream.
Consequences
Section titled “Consequences”- 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.