Agent Feedback Protocol · open spec · v0.1

Every failed
agent task is a
feature request.

Observability tells you what failed.
Backloop tells you what the agent was trying to do.

An open protocol that lets agents report what blocked them. A platform that clusters the reports, ranks them by impact and hands the fix to a coding agent. You approve the PR.

Works with
  • Claude Code
  • MCP
  • OpenAPI
  • GitHub

The missing signal

Your logs see a 200.
The agent saw a dead end.

Agents call your API for your customers. When they hit a gap, they improvise or give up. The reason never reaches your team.

What your logs capture

10:04:11Z  200  GET /companies/search?hiring_role=gtm_engineer
                total=20  unknown parameter ignored
10:04:12Z  200  GET /companies/cmp_001/jobs
10:04:12Z  200  GET /companies/cmp_002/jobs
10:04:12Z  200  GET /companies/cmp_003/jobs
… 496 more, all 200
Every call succeeded. The task didn’t.

What the agent reports

{
  "type": "missing_capability",
  "goal": "Find companies currently hiring GTM engineers",
  "endpoint": "/companies/search",
  "message": "No hiring-role filter is available",
  "workaround": true,
  "workaround_description": "500 calls to /companies/{id}/jobs"
}
The goal, the gap, and the cost of the workaround.

One endpoint

POST /feedback.
That's the protocol.

A JSON schema, a discovery document and a header on errors. Implement it in an afternoon. No vendor required.

  • GET /.well-known/agent-feedbackAgents discover the endpoint.
  • Link: </feedback>; rel="agent-feedback"Every error response points to it.
  • known_issueThe 202 tells agents a problem is already tracked, with a workaround.
  • conformance/Shared test cases. Both SDKs pass them.
Read the full spec
POST /feedback HTTP/1.1
Content-Type: application/json
Authorization: Bearer <the agent's API key>

{
  "type": "unhelpful_error",
  "goal": "Find logistics companies in the UK",
  "message": "country=United Kingdom returns 400 invalid request",
  "suggestion": "Name the parameter and the expected format",
  "outcome": "degraded"
}

HTTP/1.1 202 Accepted
{ "id": "fb_01JAX3ZK…", "status": "accepted" }

The loop

From complaint
to pull request.

Six steps between an agent hitting a wall and your team merging the fix. Five run on their own. One is yours.

  1. 01
    CollectStructured reports from every agent, de-duplicated per run.
  2. 02
    ClusterDifferent words, same problem. Grouped by intent.
  3. 03
    PrioritizeRanked by failed workflows, affected accounts and workarounds.
  4. 04
    InvestigateAn issue written from the evidence, with your API docs as context.
  5. 05
    BuildA coding agent writes the change and runs your tests in an isolated worktree.
  6. 06
    ApproveA human reviews. Only then does a draft PR open.

Signal, not noise

Twenty-four agents.
One missing filter.

From the demo dataset: 67 simulated reports from 17 accounts, clustered into 8 problems

Priority 78 of 100

Add a hiring_role filter to /companies/search

24reports
13accounts
71%blocked
29%workaround

What agents were trying to do

    Priority weighs frequency, failed workflows and affected accounts, discounted by workarounds and age. Every component is shown.

    Humans approve

    The agent proposes.
    You decide.

    • Changes run in a git worktree, never your main checkout.
    • The coding agent gets no web tools and can't push.
    • Feedback is data, never instructions, in every prompt.
    • Only text a human wrote goes back to agents.
    • Approving opens a draft PR. Merging stays with your team.

    claude-code · backloop/hiring-role-filter

    Proposed change

    Tests pass
    src/companies.js@@ -32,6 +32,9 @@ export function searchCompanies(params)   if (params.country) results = results.filter(…);+  if (params.hiring_role) {+    results = results.filter((c) =>+      c.jobs.some((job) => job.role === params.hiring_role));+  }test/companies.test.js+test("search filters by hiring role", () => { … });

    Built in the open

    Open protocol.
    Hosted loop.

    The spec and schemas are public. Any API can implement them without us. The SDKs, MCP tool and a self-hostable collector are Apache-2.0. The platform adds the part that turns reports into shipped fixes.

    Protocol & JSON SchemaSpec, discovery, conformance suite. Public today.
    TypeScript SDKClient, Fetch-API handler, redaction.
    Python SDKStandard library only. FastAPI, Flask.
    MCP toolsubmit_feedback for any MCP server.
    CollectorSelf-hosted ingestion. JSONL, Docker.
    Platform Hosted ingestion · intent clustering · prioritization · GitHub · coding agent · approvals · org controls

    A few good questions

    Before you ship it.

    Why would an agent send feedback?

    Because you ask it to. The protocol ships standard agent instructions and a tool definition. Agents using your API through MCP get submit_feedback like any other tool, and every error response links to the endpoint.

    Isn't this just error tracking?

    No. Error tracking sees the failed call. Feedback carries the goal, what was missing and what the agent did instead. Many of the useful reports come from calls that returned 200.

    What stops junk and prompt injection?

    Schema validation, per-account rate limits and de-duplication per agent run. Feedback is treated as data in every prompt. Only human-written text is sent back to agents. The coding agent gets no web tools and can't push, and nothing ships without approval.

    Do I need the platform?

    No. The protocol is open. Implement POST /feedback, store the records, read them yourself. The platform is for teams that want clustering, prioritization and the path to a PR handled.

    Which coding agents work with it?

    Claude Code today, run headless in an isolated git worktree. The agent interface is small, so others can plug in.

    Start listening

    Every agent is a user interview.
    Start taking notes.

    GET  /.well-known/agent-feedback    # advertise the endpoint
    POST /feedback                      # accept reports, return 202
    Link: </feedback>; rel="agent-feedback"  # on every error