Skip to content

feat(harness): add IBM Bob native TUI integration - #8902

Open
BrUn3y wants to merge 5 commits into
omnigent-ai:mainfrom
BrUn3y:feat/bob-native-harness
Open

BrUn3y wants to merge 5 commits into
omnigent-ai:mainfrom
BrUn3y:feat/bob-native-harness

Conversation

@BrUn3y

@BrUn3y BrUn3y commented Oct 2, 2026 •

Copy link
Copy Markdown

Related issue

Closes #8882

Summary

Current UI behavior: Omnigent forwards prompts to Bob, but Bob responses are shown only in the embedded terminal. They are not mirrored into the Omnigent chat.

IBM Bob Shell users had no way to run Bob through Omnigent. This adds bob-native, a terminal-first native harness: omnigent bob (or the web picker's IBM Bob row) runs the real bob chat TUI in a runner-owned tmux pane. Messages from the web composer are pasted into Bob's input box.

  • Registry seam. One NativeCodingAgent and provider row (key="bob", agent bob-native-ui, aliases bob and native-bob) plus a capability row. Built-in seeding, the CLI dispatch spec, lock coverage, interrupt/stop tables, readiness/install metadata (bob ≥ 2.0.0, IBM's install script), the web picker/settings/grouping rows, and the agent-terminal id are wired the way Kiro, Goose, and Qwen are.
  • Dialogs fail closed. Bob's folder-trust, license, team, and tool-approval prompts are selection lists where Enter accepts the highlighted choice ("Trust folder", "Approve Once"). A structural, locale-independent classifier (a ❯ composer row directly under a rule = ready; an ↑↓ (n/m) selector = dialog) gates every keystroke:
    • Paste is refused unless the composer is positively visible. It is re-checked immediately before paste-buffer and again before the single Enter, and the staged buffer is deleted on refusal.
    • Stop's Escape is sent only on a READY pane. On the trust or sign-in screen, Escape would exit Bob.
    • The web turn fails with "Bob is waiting on a prompt in its terminal" until the user answers it there.
  • No silent bypasses.
    • Omnigent never adds --trust, --accept-license, or --auto-approve.
    • Pass-through args are allowlisted to documented bob chat options. --auto-approve, --workspace, --model, unknown options, and empty inline values are rejected, both in the CLI (before any backend starts) and at runner launch for persisted args.
    • Bob is excluded from harness_supports_model_override, and a persisted model or effort override is refused at launch instead of being silently dropped.
  • Narrow environment. The Bob terminal uses inherit_env=False with an allowlist: PATH, HOME, locale, terminal, HTTP(S)_PROXY/NO_PROXY, NODE_EXTRA_CA_CERTS, BOB_LOG_LEVEL. Bob's BOB_API_KEY is deliberately not forwarded; through Omnigent, Bob uses the IBMid login it stores in ~/.bob. OMNIGENT_BOB_PATH (non-secret) now survives the CLI → daemon → runner hops, like OMNIGENT_CODEX_PATH.
  • Not advertised: model or effort pickers, approval cards or policy integration, fork history, Omnigent sub-agents, hooks, and chat-transcript mirroring. Capabilities: elicitation=none, fork_history=none, subagents=false, streaming=false. The bench manifest now declares model_override, tool_calling, and policy_deny as unsupported for Bob.

Architecture tradeoff: Bob 2.0.2+ also documents bob acp, which could be a one-row ACP harness. It is not used because it would not give users Bob's own interactive TUI. It is a possible follow-up.

Test Plan

Environment: macOS, Python 3.12, Node 25.2, pnpm 11.15.1, tmux, IBM Bob Shell 2.0.5 (upgraded from 1.0.6 with IBM's checksum-verified installer).

  • uv run --no-sync pytest -q tests/test_bob_native.py → 75 passed. Covers:
    • identity and aliases
    • capabilities
    • install spec and version floor (2.0.5/2.0.0 pass, 1.0.6 fails)
    • readiness gating and catalog setup steps
    • agent-spec seeding
    • argv allowlist: accept, reject, and empty values
    • CLI rejection before backend start
    • terminal env allowlist (secrets dropped)
    • runner launch argv/env, and refusal of persisted --auto-approve and model/effort overrides
    • pane classification on trimmed real 2.0.5 captures
    • paste, interrupt, and dialog-transition fail-closed paths
    • executor error surfacing
    • warm-reattach resume and wrong-harness rejection
    • model-override exclusion
    • bench declarations
  • uv run --no-sync pytest -q -p no:cacheprovider tests/test_bob_native.py tests/cli/test_host_daemon_env.py → 105 passed. The three run --harness Bob spellings reject --model before _ensure_backend; focused native-dispatch/help tests add 55 passed.
  • Affected backend suites (tests/runner tests/onboarding tests/cli tests/host tests/native tests/harness_bench tests/dev tests/server/test_app.py tests/server/test_builtin_bundles.py plus the harness registry, capability, and alias tests) → 8013 passed, 26 failed. All 26 failures also fail on clean main in this environment (see below).
  • Full unit suite (pytest -n 8 --dist=loadfile) → 33207 passed, 82 failed. Re-running the 24 affected files on clean main reproduces 63 of them. The remaining 23 (deploy/entrypoint/guardrails/legal-files) pass when run in isolation on this branch (70 passed), so they are xdist ordering flakes. The pre-existing failures are environment-dependent: the local ~/.claude/Codex login, a DB token callback, and timing.
  • uv run --no-sync ruff check / ruff format --check (changed files) → clean.
  • uv run --no-sync pyrefly check → 0 errors.
  • uv run --no-sync pre-commit run --all-files → all hooks pass. The VS Code hook needed pnpm install --frozen-lockfile --filter ./editors/vscode first.
  • git diff --check → clean.
  • Web:
    • pnpm run lint → pass; pnpm run type-check → pass; pnpm run build → pass.
    • LANG=en_US.UTF-8 NODE_OPTIONS=--no-experimental-webstorage pnpm test → all pass. Without those settings the failures are pre-existing environment issues: Node 25's built-in localStorage shadows jsdom, and 4 number-formatting tests are locale-sensitive under es_ES.
    • Includes new nativeCodingAgents (Bob resolution, native-bob alias, no picker capabilities), useTerminals (terminal_bob_main is the agent pane), and AgentCard (generic icon fallback) cases.
  • Live smoke (real Bob, real account), isolated Omnigent state, with both Bob key variables stripped:
    env -u BOBSHELL_API_KEY -u BOB_API_KEY \
      OMNIGENT_CONFIG_HOME=$(mktemp -d) OMNIGENT_DATA_DIR=$(mktemp -d) OMNIGENT_E2E_BOB_NATIVE=1 \
      uv run --no-sync pytest tests/e2e/test_bob_native_cli_e2e.py --llm-api-key dummy -v
    → 1 passed (8.5s). omnigent bob --server … -- --trust launched bob chat --trust in a runner-owned tmux pane in a disposable directory. A POST /v1/sessions/{id}/events message (the web path) reached Bob, and Bob's one-word marker reply appeared in its pane. The pane was then killed, with no Bob, tmux, host, or runner processes left behind.
  • Secret hygiene: a scan of every smoke and demo log, the evidence files, and git diff found 0 occurrences of the Bob key value. No fixture, snapshot, or test contains a credential.

Demo

  • Visual demo attached below
  • Non-visual evidence provided below or in Test Plan
  • Not applicable — no behavioral change

New-session picker on an isolated local server and host. IBM Bob is listed under Harnesses → Other with the generic bot-icon fallback (no IBM artwork). It is enabled because Bob 2.0.5 is installed; the other natives show the not-installed warning. The screenshot is cropped to exclude local paths.

Screenshot 2026-10-02 at 6 11 02 p m Screenshot 2026-10-02 at 6 10 41 p m

GET /v1/agents on the same freshly seeded server includes {"name": "bob-native-ui", "harness": "bob-native"}, and GET /v1/harnesses → setup_steps["bob-native"] lists the install step.

Type of change

  • Bug fix
  • Feature
  • UI / frontend change
  • Refactor / chore
  • Docs
  • Test / CI
  • Breaking change

Test coverage

  • Unit tests added / updated
  • Integration tests added / updated
  • E2E tests added / updated
  • Manual verification completed
  • Existing tests cover this change
  • Not applicable

Coverage notes

Manual verification:

  • Ran Bob 2.0.5 in scratch tmux sessions with an isolated HOME to capture the real trust dialog, browser sign-in wait, ready composer (English and es_ES locales), mid-turn "Enter to steer", and tool-approval dialog that the classifier fixtures are trimmed from.
  • Confirmed bracketed multi-line paste, /exit clean termination, and that a single Ctrl+C on an empty composer only arms exit (which is why drafts are not cleared).
  • Drove the web picker in the browser (screenshot above).
  • The opt-in e2e smoke was run live as described in the Test Plan. It is skipped in CI because it needs a signed-in Bob account.

Not verified live: Escape interrupting a streaming Bob turn (it is Bob's documented key, and the fail-closed paths are unit-tested), web Stop / Stop session on a live Bob session, and Bob 2.0.0–2.0.4 (the floor is the documented 2.x CLI boundary; only 2.0.5 was driven).

Release notes

Should this change be included in the release notes? Choose exactly one.

  • No — no noteworthy user-facing change.
  • Yes — include the entry in the Changelog section.

Changelog

omnigent bob and the web picker's IBM Bob entry run IBM Bob Shell 2.x's own bob chat TUI as a native harness. Bob's sign-in, license, folder-trust, and tool-approval prompts stay in Bob's terminal.

@github-actions github-actions Bot added P2-medium Priority: bug with workaround, important feature request size/XL Pull request size: XL labels Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

✅ This PR no longer requires demo follow-up.

@github-actions github-actions Bot added needs-demo PR needs a demo screenshot or recording waiting-for-review labels Oct 2, 2026
@github-actions
github-actions Bot requested a review from daniellok-db October 2, 2026 23:38
@github-actions github-actions Bot added P1-high Priority: major feature broken, no workaround and removed P2-medium Priority: bug with workaround, important feature request needs-demo PR needs a demo screenshot or recording labels Oct 3, 2026
Signed-off-by: Bruney <[email protected]>

# Conflicts:
#	web/src/pages/settings/SettingsCustomizeSection.tsx
Resolve native runner conflicts using the shared launch lock registry, preserve Bob executable forwarding, and retain both orchestration helpers. Keep Bob excluded from idle reaping because its terminal context cannot be restored.

Signed-off-by: Bruney <[email protected]>
@BrUn3y

BrUn3y commented Nov 3, 2026

Copy link
Copy Markdown
Author

@daniellok-db I've merged the latest main and resolved the conflicts in commit ef2f0cd. Bob now uses the shared runner launch lock registry, while preserving the upstream orchestration and environment changes. Idle-reaper coverage also accounts for Bob's terminal context not being restorable.

Validation after the merge:

  • pre-commit run --all-files: all hooks passed.
  • Focused Python suites: 1,373 passed, 1 skipped. Two Claude model-catalog tests fail with identical assertions on clean main (5d9f5a08e) in this environment.
  • Frontend: 125 tests passed, and the production build passed.

Could you please review this PR when you have a chance? Thank you!

This branch has not been deployed

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

Labels

P1-high Priority: major feature broken, no workaround size/XL Pull request size: XL waiting-for-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add IBM Bob Shell as a native TUI harness (bob-native)

2 participants