Skip to content

ax agents update --bio / --specialization silently dropped — server ignores fields #76

@michaelschecht

Description

@michaelschecht

Summary

ax agents update --bio "..." and ax agents update --specialization "..." report success (Updated agent: X) but the fields are never persisted. --description on the same command works correctly. Verified against authoritative GET via the ax-platform MCP agents.list endpoint after each attempt.

Version

  • axctl 0.3.0 (pipx) → ax_cli 0.1.0
  • base_url: https://next.paxai.app
  • PAT class: axp_u_* (user PAT), exchanging to user_access JWT

Reproduction

ax agents update Edge-Hunter \
  --bio "Phase 1/3 — Pre-trade scanner" \
  --specialization "Pre-trade: market scanning, cross-reference, validation"
# → Updated agent: Edge-Hunter   (exit 0)

Then inspect the agent record (authoritative source — ax agents get --json does not expose these fields):

# via ax-platform MCP agents.list
{
  "name": "Edge-Hunter",
  "description": "...",            # persisted ✅
  "bio": null,                     # dropped ❌
  "specialization": null,          # dropped ❌
  ...
}

description set in the same command call round-trips correctly. Only bio and specialization are silently discarded.

Expected Behavior

Either:

  • The fields persist and are returned by the agent record; or
  • The server returns an error (e.g., 400) so the CLI can surface it.

The current behavior (HTTP 200 + silent drop) gives users a false-success signal.

Root Cause — Client Side Is Fine

The CLI correctly packs bio/specialization into the PUT body:

  • ax_cli/commands/agents.py:142-145 — packs into fields dict
  • ax_cli/client.py:459-463update_agent PUTs fields to /api/v1/agents/manage/{identifier}
# ax_cli/commands/agents.py
if bio is not None:
    fields["bio"] = bio
if specialization is not None:
    fields["specialization"] = specialization
...
client.update_agent(identifier, **fields)

# ax_cli/client.py
def update_agent(self, identifier: str, **fields) -> dict:
    r = self._http.put(f"/api/v1/agents/manage/{identifier}", json=fields)

So the CLI sends the fields over the wire. The drop happens server-side.

Cross-Endpoint Verification

Tested every public write path exposed by the CLI source against the same agent. Each call used a valid JWT obtained via POST /auth/exchange. Verified state after each call via MCP agents.list (the authoritative read path that returns bio/specialization):

Endpoint JWT class HTTP status bio persisted specialization persisted
PUT /api/v1/agents/manage/{id} (CLI default) user_access 200
PATCH /agents/manage/{id} (management API) user_admin + agents.create 200
PATCH /api/v1/agents/{id} user_access 405 Method Not Allowed n/a n/a

Impact

  • Users building multi-agent setups cannot programmatically populate the bio/specialization fields that the web UI surfaces on agent profile cards.
  • Today the only working path to set these fields is the AX web UI (confirmed — agents created in the UI with a bio retain it across agents.list fetches, while agents updated via the CLI/API never gain one).
  • The silent-success behavior makes this hard to diagnose without reading ax_cli source and the MCP agents.list response shape.

Suggested Fix (server-side)

Most direct: have PUT /api/v1/agents/manage/{id} (and/or PATCH /agents/manage/{id}) persist bio and specialization when present in the body. Either of these endpoints is fine as the canonical write path; the CLI is wired to the PUT variant.

Suggested Fix (CLI-side, if server won't change)

If server persistence remains description-only by design, either:

  1. Remove the --bio / --specialization flags from ax agents update, or
  2. Emit a clear warning (NOTE: bio/specialization are currently only settable via the web UI) when those flags are passed.

Either would prevent the false-success pattern.

Environment

  • Windows 11, Python 3.12.10
  • axctl 0.3.0 via pipx
  • MCP client: Claude Code (ax-platform HTTP MCP at https://next.paxai.app/mcp/agents/Edge-Radar-Scriptor)
  • Space has 5 agents in it, all owned by the caller

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions