Hyperstruck

Learning loop

Give the agents you already run access to what prior runs learned, with a resolve before the work and an observe after it.

In one line

Two calls wrap the work your agent already does: resolve before it starts, observe when it finishes. Everything else is Hyperstruck's job.

This is the path for agents you already run, on your own framework, in your own process. Hyperstruck sits underneath and never takes over the loop. If you want Hyperstruck to own planning and execution instead, that is the Engine, and it is a different starting point.

The pairing

CallWhenWhat it does
resolveBefore the agent acts, with the goalReturns the learnings prior runs earned that fit this goal, plus the identifiers of what was offered.
observeAfter the run finishes, with the same run_idSubmits the finished episode so the outcome credits what helped and new learnings are extracted from what happened.

The run_id is yours. It is a correlation key you invent, not a hosted resource identifier, and reusing the same value across both calls is what lets Hyperstruck attribute the outcome back to the learnings it offered.

Extraction is asynchronous

observe returns 202 Accepted. Learnings are extracted in the background, so a lesson from the run you just submitted is not retrievable the instant the call returns. By the time a similar task comes around, it is in place.

LangGraph

The shortest path. Register one middleware and your existing agent keeps its model, its tools, and its graph.

from hyperstruck.langgraph import HyperstruckLearningMiddleware

async with HyperstruckLearningMiddleware(
    api_key="<YOUR_HYPERSTRUCK_API_KEY>",
    agent_id="support-agent",
) as learning:
    agent = create_agent(model, tools=tools, middleware=[learning])
    result = await agent.ainvoke({"messages": [("user", "Triage ticket SUP-2048")]})

Install it with pip install hyperstruck[langgraph]. The middleware resolves at run start and observes at run end, so neither call appears in your code. Other frameworks are covered in framework integrations.

REST

Any language, no SDK. The two calls below are the whole loop.

curl -X POST "https://api.hyperstruck.com/resolve" \
  -H "Authorization: Bearer <YOUR_HYPERSTRUCK_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "support-agent",
    "run_id": "support-agent:ticket-2048:attempt-1",
    "goal": "Triage ticket SUP-2048 and recommend the next action."
  }'

curl -X POST "https://api.hyperstruck.com/observe" \
  -H "Authorization: Bearer <YOUR_HYPERSTRUCK_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "support-agent",
    "episode": {
      "run_id": "support-agent:ticket-2048:attempt-1",
      "goal": "Triage ticket SUP-2048 and recommend the next action.",
      "steps": [{ "id": "step-1", "name": "ticket_lookup" }],
      "outcome": { "is_success": true }
    }
  }'

resolve returns injected_text, ready to place in front of your model, and offered_learning_ids for the entries it drew on. Put injected_text where your agent will actually read it, then run the work as normal.

Resolve fields

Only agent_id, run_id, and goal are required.

FieldDefaultNotes
agent_idrequiredYour own identifier for the agent, not a hosted UUID.
run_idrequiredYour correlation key. Reuse it with observe.
goalrequiredWhat the agent is about to attempt.
available_tools[]Tool names and descriptions, so lessons about a tool reach the runs that can use it.
max_learnings8Between 1 and 50.
retrievalfastfull trades latency for richer context.
source_framework""Attributes the per-host funnel, for example mcp:cursor.

Observe fields

The episode wants a real execution trace. Steps default to completed, so a failed step needs "status": "failed" set explicitly, and an honest failure is worth more to the corpus than a tidy success.

FieldDefaultNotes
agent_idrequiredMatches the value used at resolve.
episode.run_idrequiredThe same key you resolved with. Also the idempotency key.
episode.goalrequiredThe goal that was attempted.
episode.stepsrequiredEach step needs id and name. args, result, and error are optional.
episode.outcome.is_successrequiredWhether the episode achieved its goal.

Send the trace, not documents

observe is for what your agent actually did. To contribute reference material rather than execution evidence, use distill instead, which is built for corpus content.

Other surfaces

The same loop reaches Hyperstruck through several front doors, and learnings captured one way are available to every other.

  • MCP exposes resolve and complete_run as tools to Claude Code, Cursor, and any other MCP host.
  • Claude Code and Cursor skills drive it from a slash command inside your IDE.
  • Framework integrations cover LangGraph, the OpenAI Agents SDK, and CrewAI.
  • Learnings API is the manual control surface for storing, searching, and reinforcing specific lessons by hand.