Skip to content

Codex app-server Kanban workers cannot complete tasks under sandbox without board DB writable root #26203

@hehehe0803

Description

@hehehe0803

Bug description

When Hermes workers use model.openai_runtime: codex_app_server, Kanban-dispatched tasks can complete their actual work but fail the board handoff because Codex's workspace sandbox cannot write the Kanban SQLite DB outside the task workspace.

Observed result: the worker prints a successful final answer in its task log, but kanban_complete / kanban_block cannot update the board DB, so the dispatcher later marks the task crashed / blocked.

This is a sandbox integration issue, not a domain-task failure.

Environment

  • OS: Ubuntu 24.04 / Linux
  • Codex CLI: codex-cli 0.130.0
  • Hermes runtime: model.openai_runtime: codex_app_server
  • Worker profiles tested: backend-worker, frontend-worker, fullstack-worker
  • Sandbox: Bubblewrap/AppArmor working; profile configs use default_permissions = ":workspace"

Reproduction shape

  1. Configure worker profiles to use Codex app-server runtime.
  2. Ensure direct profile smoke passes:
    hermes -p backend-worker chat -q 'Run a harmless shell command and reply ok' --yolo -Q
  3. Create a disposable Kanban board and a scratch task assigned to a Codex-runtime worker:
    BOARD=codex-runtime-orchestration-smoke
    hermes kanban boards create "$BOARD" --switch || hermes kanban boards switch "$BOARD"
    hermes kanban --board "$BOARD" create "Smoke backend-worker Codex app-server runtime via Kanban" \
      --assignee backend-worker \
      --workspace scratch \
      --priority 100 \
      --max-runtime 5m \
      --max-retries 1 \
      --body "Smoke only. Print CODEX_HOME and pwd, then call kanban_complete with summary 'backend-worker codex runtime smoke ok'. If that fails, call kanban_block with exact reason."
    hermes kanban --board "$BOARD" dispatch --max 1
  4. Poll / inspect:
    hermes kanban --board "$BOARD" list
    hermes kanban --board "$BOARD" show <task_id>
    hermes kanban --board "$BOARD" runs <task_id>
    hermes kanban --board "$BOARD" log <task_id>

Actual behavior

Worker logs show the underlying smoke succeeded, e.g. CODEX_HOME and pwd printed correctly. But the handoff fails because the sandbox cannot write the board DB:

Blocked: sqlite3 could not open the kanban database for writing from this sandbox
...
unable to open database file

or:

The smoke check passed ...
I could not mark the Kanban task complete because writing to the board database failed under the sandbox

Dispatcher then records the run as crashed / blocked, even though the task itself completed.

Expected behavior

A Kanban worker running on Codex app-server should be able to:

  • keep Codex sandboxing enabled,
  • execute inside its assigned scratch/worktree workspace,
  • call Hermes MCP callback tools like kanban_complete / kanban_block, and
  • write only the current board DB/handoff path needed for task lifecycle updates.

It should not require danger-full-access or :danger-no-sandbox.

Proposed fix

When spawning codex app-server for a dispatcher-spawned worker (HERMES_KANBAN_TASK present), pass narrow Codex config overrides:

if HERMES_KANBAN_TASK:
    board_dir = dirname(HERMES_KANBAN_DB)
    codex app-server \
      -c 'sandbox_mode="workspace-write"' \
      -c 'sandbox_workspace_write.writable_roots=["<board_dir>"]' \
      -c 'sandbox_workspace_write.network_access=false'

Why board dir rather than all of ~/.hermes/kanban:

  • HERMES_KANBAN_DB is already pinned by the dispatcher to the current board.
  • Per-board directory is the minimal writable root needed for SQLite kanban.db, journals/WAL files, logs/events if needed.
  • It preserves board isolation and avoids giving workers write access to unrelated boards or the whole Hermes home.

Security posture:

  • sandbox remains enabled (workspace-write),
  • no danger-full-access,
  • no :danger-no-sandbox,
  • no network by default,
  • only the current board directory becomes an extra writable root.

Validation performed locally

After applying the narrow writable-root bridge locally:

  • Direct worker runtime smoke passed for all workers.
  • MCP callback smoke passed (web_extract via Codex runtime).
  • Real Kanban dispatcher smoke passed on a disposable board:
    • backend-worker: task reached done
    • frontend-worker: task reached done
    • fullstack-worker: task reached done
  • Targeted tests passed:
    80 passed in 4.76s
    
    for:
    python -m pytest tests/agent/transports/test_codex_app_server_runtime.py tests/agent/transports/test_codex_app_server_session.py -q

Local patch touched:

  • agent/transports/codex_app_server.py
  • tests/agent/transports/test_codex_app_server_runtime.py
  • website/docs/user-guide/features/codex-app-server-runtime.md

Happy to open a PR with this patch if maintainers agree with the writable-root approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/agentCore agent loop, run_agent.py, prompt buildercomp/cronCron scheduler and job managementsweeper:implemented-on-mainSweeper: behavior already present on current maintool/terminalTerminal execution and process managementtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions