Decision API (System 1 / System 2)

SkillCommunication

decision-api is a skill that sets up a two-part loop for real-time, low-latency tasks such as games or device control. A fast decision model, called System 1, picks each action from observations, while the agent, System 2, routes high-level goals to it as messages. The agent designs what System 1 sees, tunes its instructions and settings, and improves the loop by comparing runs and updating goals. It requires the decisionApi.systemOneModel setting to be configured before it works.

Then ask your AI: use the Decision API (System 1 / System 2) skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Configure the decisionApi.systemOneModel setting with a resolvable model reference.

What your AI can do with it

  • Spawns a decision child that serves one decision per observation
  • Routes updated goals to the decision child with loop.set_goal
  • Reports the model that served each decision via loop.status
  • Lets the agent tune state, instructions, history_size, tick, and decide_timeout
  • Compares runs under the same conditions to improve the loop

Getting started

  1. Configure the decisionApi.systemOneModel setting with a resolvable model reference.
  2. Spawn the decision child with rlm.spawn(kind="decision").
  3. Set the objective and optionally route goals with loop.set_goal.
  4. Run the loop and inspect loop.history and loop.goal_updates to diagnose results.

What this skill tells your AI

The instructions your AI receives, as published by primeintellect-ai/prime-agent in skills/decision-api/SKILL.md and read by Ahel’s review.

Use this for real-time control tasks where every step is one choice from an action set (a game, a device, a UI) and a full agent turn per step is too slow.

  • System 1 is the decision model the user configured: the decisionApi.systemOneModel setting names it. The canonical target is Prime Inference's hosted structured-decision clef (prime-inference/cloudflare/clef, served at https://api.pinference.ai/api/v1 with the stored login's team header); any registry model reference that resolves can serve the role, and a resolvable reference turns the feature on. Loop spawns it as a decision child (rlm.spawn(kind="decision")) whose every message is one decision request: each observation becomes one model call that returns the chosen action and its confidence. The child lives exactly as long as the loop. loop.status()["system1_model"] reports the model that served each decision.
  • System 2 is you, the parent running the loop. loop.set_goal("...") routes updated goals to the child as tagged agent messages, and every decision the child serves reads the latest goal. Goals are one or two sentences of strategy, never an action name or a step-by-step command.

Your role: optimize the whole loop

You own the loop's design and performance:

  • what System 1 sees (state, and images with a vision-capable model);
  • how its question reads (instructions and the action descriptions);
  • its history_size, tick, and decide_timeout;
  • the goals you route with set_goal and the objective they refine.

Writing the task's strategy into System 1's instructions and action descriptions is loop design, not goal routing.

Diagnose from the outcome before changing anything. The task's own result (score, success rate) is the measure; loop.history confidences and loop.goal_updates explain it.

  • System 1 problems: low confidence, actions flipping between options, or failures while the goal stays the same. Give state the information the decision needs, sharpen instructions, or make the action descriptions easier to tell apart.
  • Goal problems: goals that are wrong, churn, or lag the situation. Update the goal only when the situation genuinely needs a new direction; loop.goal starts as the objective.
  • No goals needed: for pure reflexes or one fixed strategy, never call set_goal; the objective alone is enough.

Change one thing at a time and compare runs under the same conditions (same seed or scenario, same duration), keeping what measurably helps. Make changes through the loop's settings or the task's own code, never by editing this skill's package. Do the analysis yourself rather than delegating it to extra subagents.

You never steer the live loop by hand:

  • Do not choose actions from observations yourself.
  • Do not message the decision child directly; set_goal is the route.
  • loop.goal is yours (it starts as the objective): set_goal updates it live.

Setup

The Decision API is off until configured: the user sets decisionApi.systemOneModel in settings.json to a registry model reference ("provider/model-id" or a bare id) and restarts the session or kernel. The host resolves the model and its credentials through the model registry — the same path any other model call takes — and makes every provider call. If a call reports the setting is unset or unresolvable, ask the user to fix the setting. Do not ask for keys yourself.

Usage

Write observe and act for the environment (sync or async), start the loop in the background, then watch and adjust it from later cells:

actions = {
    "left": "Move left when the target is to the left",
    "right": "Move right when the target is to the right",
    "wait": "Do nothing when already aligned",
}
loop = decision_api.Loop(observe, act, actions, objective="Keep the paddle under the ball", tick=0.3)
loop.start()

status = await loop.wait(timeout=20)   # returns early if the loop ends
print(status, loop.history[-5:], loop.goal_updates[-3:], loop.errors[-3:])

Every attribute is read again each step, so assignments take effect live:

loop.actions["fire"] = "Fire when an enemy is straight ahead"   # or a function (observation) -> dict
loop.instructions = "..."; loop.tick = 0.2
loop.state = lambda observation, goal, history: {...}           # exactly what System 1 sees
loop.images = lambda observation: [png_data_url]                # vision models: up to 4 images per step
loop.on_error = "skip"            # "stop" (default), "skip", or (error, observation) -> action
loop.on_step = lambda record, observation: ...                  # log or render; return "stop" to end the loop
loop.set_goal("Prioritize catching the ball over waiting")      # System 2: route a new goal to the child
loop.objective = "..."           # the goal's fallback; set_goal overrides it
loop.decide_timeout = 30.0       # bound one decision round trip
loop.pause(); loop.resume()
final = await loop.stop()        # also removes the decision child

Construction accepts the same settings as keywords (decide_timeout=10, max_steps=500, history_size=10, ...); help(decision_api.Loop) lists all of them. await loop.run() runs to completion in one cell instead.

Each step sends one decision request to the child and awaits its tagged reply. Spawn and delivery failures appear in loop.errors (spawn retries in the background); a decision that overruns decide_timeout fails the step and follows on_error. Stopping removes the child. Python 3.11 or newer is required.

Stay in your turn while a loop runs: poll with loop.wait(timeout=...), read history, goal_updates, and errors, adjust, and stop it when done. The loop keeps running between cells, but nothing wakes you once your turn ends.

For a single System 1 decision without a loop, await decision_api.decide(observation, actions, goal="...", images=None) returns action, confidence, probabilities, latency_ms, and model — the same host call the child serves.

Images (vision-capable models only): at most 4 per decision, each a data URL string such as f"data:image/png;base64,{base64.b64encode(png_bytes).decode()}" (not bytes, paths, or dicts); PNG, JPEG, or WebP, up to 4 MiB and 16 megapixels each and 8 MiB in total. Small, cropped images keep latency low; degenerate ones (a 1x1 pixel) fail with a server error.

Signals

GitHub stars
22k
Forks
2k
Last commit
Oct 2026

Questions

What is the decisionApi.systemOneModel setting?
It names the model that serves as System 1. The canonical target is Prime Inference's hosted structured-decision clef, but any registry model reference that resolves can serve the role. A resolvable reference turns the feature on.
How do I set a goal for the decision model?
Call loop.set_goal with one or two sentences of strategy. Goals are routed to the child as tagged agent messages, and every decision reads the latest goal. Do not use an action name or step-by-step command.
What does loop.status report?
loop.status()["system1_model"] reports the model that served each decision.
Advanced
Item type
skill
Key
decision-api
Source
github.com/primeintellect-ai/prime-agent