Skip to content

Proposal: Agent-oriented API design — tools should return structured JSON, not CLI text #23

@Tweakzx

Description

@Tweakzx

Problem

The current OpenClaw plugin tools shell out to the Python CLI and return raw stdout text:

// Current: agentflow_task_detail
async run(input) {
    const result = await runAgentflow(["task-detail", "--task-id", String(input.task_id)]);
    return { content: result.stdout || result.stderr };
    // Returns: "id  project  status  pri imp eff score  ..."
}

This means the agent must parse fixed-width text to extract structured data. This is:

  • Fragile — column widths might change
  • Lossy — some fields (description, PR URL) are not in the CLI output
  • Slow — every tool call spawns a Python process
  • Unreliable — stderr might be mixed with stdout

Proposal: Agent-first API design

The plugin tools should return structured JSON objects that the agent can directly use in reasoning and tool calls.

Example: agentflow_task_detail

Before:

id  project  status       pri imp eff score  agent         lease_until           title
7   demo     in_progress  5   4   2   7.0    codex-worker  2024-01-01 12:00:00  Fix auth crash

After:

{
  "ok": true,
  "task": {
    "id": 7,
    "project": "demo",
    "title": "Fix auth crash",
    "status": "in_progress",
    "priority": 5,
    "impact": 4,
    "effort": 2,
    "score": 7.0,
    "assigned_agent": "codex-worker",
    "lease_until": "2024-01-01T12:00:00Z",
    "pr_url": null,
    "source": "github",
    "external_id": "42"
  },
  "runs": [...],
  "history": [...]
}

Example: agentflow_create_task

Before: Returns "task created: 7" — agent does not know the task object.

After: Returns the full task object so the agent can immediately use task.id in subsequent calls.

Example: agentflow_board

Before: Returns a text table.

After: Returns structured data with stage groupings:

{
  "ok": true,
  "project": "demo",
  "stages": {
    "collected": [...],
    "triaged": [...],
    "executing": [...],
    "review": [...],
    "done": [...],
    "blocked": [...]
  },
  "summary": {
    "total": 12,
    "in_progress": 3,
    "blocked": 1,
    "completed": 8
  }
}

Why This Matters for Agent Reliability

The #1 reason codex-orchestrator is unstable is that the agent cannot reliably read and write task state. When tools return text instead of JSON:

  1. Writing: Agent calls add-task --title "fix bug" → gets back "task created: 7" → must parse "7" from text to know the task ID
  2. Reading: Agent calls board → gets a text table → must parse to find task IDs, statuses, agents
  3. Updating: Agent calls move 7 pr_ready → no confirmation of the new state

With structured JSON:

  1. Writing: Agent gets { task: { id: 7, ... } } → has the ID immediately
  2. Reading: Agent gets { stages: { executing: [{ id: 7, agent: "codex", ... }] } } → can directly check status
  3. Updating: Agent gets { ok: true, task: { id: 7, status: "pr_ready", ... } } → confirmed

Implementation Path

  1. Add --json flag to CLI commands (board --json, task-detail --json --task-id 7)
  2. Update plugin tools to use --json and parse the result
  3. Return parsed JSON as the tool response

Or (better for TS plugin path): tools call store functions directly, no CLI bridge.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions