CodingOpen SourceFreeActiveMachine-verified· advanced · ~20 min setup

OpenHands + Fable 5: Autonomous Issue to Pull Request

Hand Fable 5 a GitHub issue and let OpenHands plan, edit, run tests, and open a PR in a Docker sandbox.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 4/4 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Watching an agent run autonomously: OpenHands works in a Docker sandbox with shell, editor, and browser, turning an issue into a PR. CI verifies the deterministic spine: the settings config parses, llm.model equals anthropic/claude-fable-5, and the runtime and agent keys are present and well-typed. No key. The agent reading the issue and writing the fix is the fenced model step.

Not for

  • Giving an autonomous agent --always-approve on a real repo; keep confirmation mode on for anything that pushes
  • Setups without a working Docker socket (the default runtime)
  • Expecting CI to verify the PR; that is the fenced model step

The Stack

Tested Against

openhands@1.8.xclaude-fable-5

Side effects & data flow

Network
none, local only
Writes
./settings.json, ./checkopenhands.mjs
Credentials
none required

Prerequisites

  • Docker (default runtime)
  • uv (uv tool install openhands --python 3.12)
  • An Anthropic API key for anthropic/claude-fable-5

Steps

  1. 1

    Install OpenHands and set Fable as the model

    uv tool install openhands --python 3.12, then openhands -t 'Reproduce and fix the bug in issue #142, add a regression test, open a PR'. Set the model on first run or in settings: the [llm] block is model = anthropic/claude-fable-5, api_key = <your key>.

  2. 2

    What CI checks: the settings parse and name Fable

    CI confirms the settings config parses, llm.model equals anthropic/claude-fable-5, and the runtime and agent keys are present and well-typed. Deterministic, no key. The autonomous run is fenced.

    cat > settings.json <<'EOF'
    { "llm": { "model": "anthropic/claude-fable-5", "api_key": "<your-anthropic-key>" }, "runtime": "docker", "agent": "CodeActAgent" }
    EOF
    cat > checkopenhands.mjs <<'EOF'
    import { readFileSync } from 'node:fs';
    const cfg = JSON.parse(readFileSync('settings.json', 'utf8'));
    let ok = true;
    function check(label, cond){ console.log(label + ': ' + (cond ? 'yes' : 'NO')); if(!cond) ok=false; }
    check('settings parse', true);
    check('llm.model is anthropic/claude-fable-5', !!cfg.llm && cfg.llm.model === 'anthropic/claude-fable-5');
    check('runtime key present and typed', typeof cfg.runtime === 'string' && cfg.runtime.length > 0);
    check('agent key present and typed', typeof cfg.agent === 'string' && cfg.agent.length > 0);
    if(!ok){ console.log('openhands config check FAILED'); process.exit(1); }
    console.log('openhands config check OK: llm.model anthropic/claude-fable-5');
    EOF
    node checkopenhands.mjs
  3. 3

    Let it open the PR (the model step, not checked by CI)

    OpenHands runs Fable in the sandbox to fix the issue and open a PR. That is non-deterministic and is fenced. Keep confirmation mode on for anything that pushes.

Eval, 4 fixtures

Last passed: verified today
  • llm-modelcontainstimeout 30s · max $0

    Expected: llm.model is anthropic/claude-fable-5: yes

  • runtime-keycontainstimeout 30s · max $0

    Expected: runtime key present and typed: yes

  • check-okcontainstimeout 30s · max $0

    Expected: openhands config check OK: llm.model anthropic/claude-fable-5

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

~76.4k stars; where Fable's token efficiency compounds hard, an agent that loops for hundreds of steps.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).