Open Spec For Reason In Action

Re in Act

Re in Act extends reason into the action loop, so local disturbances are handled before they turn into extra round trips, noisy context, and brittle control in traditional ReAct agents.

Set the goal and guardrails once. Let small decisions happen where the work happens.

Read More

Start Here

Start with the docs, read the spec, dig into the rationale, or join the project.

From ReAct to Re in Act

How the flow changes: less stop-and-think, more structured action.

01

Paradigm Shift

ReAct returns to the outer loop at every step. Re in Act keeps the work moving inside one RAS.

Legacy
Modern
Thin Action LayerRAS Strengthens Local Action
Round-Trip Tax (Reason-Act-Observe)One Orchestrated Action Phase
Raw Intermediate Data in Main ContextIntermediate Data Stays in RAS
Probabilistic Micro-Control FlowDeterministic Runtime Control Flow
No Local Structure During ActionIntermediate Data + Judgment Inside Action
02

Local Action Space

One RAS can coordinate multiple act() and reason() steps before returning a denoised result.

1
act() gathers local evidence

Run tests, read logs, or fetch a document without pushing raw output back to top-level reasoning.

act('bash', 'npm test -- --reporter json')
2
reason() compresses the local signal

Turn noisy evidence into one bounded decision using an explicit goal, observation, relevant context, and constraints.

reason([ 'Goal: identify the best retry step.', observation, 'Relevant context: CI run after latest change.', 'Constraints and rules: return retry_cmd + reason only.', ], { retry_cmd: '', reason: '' })
3
act() + reason() keep the space moving

Execute the next step, inspect the result again, and only return a denoised outcome once the local job is actually settled.

act('bash', retry_cmd) -> reason(...) -> act('deploy' | 'notify')
03

Two Action Forms

The same idea can run as code or shell pipelines. In both forms, deterministic Turing-complete control is stronger than probabilistic LLM-stepped flow.

The Interfaces

Two simple interfaces: one for local judgment, one for external action.

01

reason(prompt, example_output)

Turns goal plus local reality into structured output that the RAS can use right away.

reason ( prompt, example_output )
{
1"prompt""Goal: decide continue vs retry. Observation: noisy build log. Constraints: ignore ANSI noise; return action + reason.",// goal + observation + context + constraints
2"example_output"{"action": "continue", "reason": ""},// schema hint
3"→ data"{"action": "retry", "reason": "registry timeout"},// structured result
4"→ error""validation failed after 3 retries"// on failure
}
02

act(name, args) — Optional

Calls tools or external systems with explicit arguments, returning structured output and errors.

act() is optional — the spec provides it as a standard convenience. You may use any user-defined action strategy instead.
MUSTnameTool identifier — MCP tool, custom function, bash command, etc.
MUSTargsComplete tool arguments. Stateless — include all needed context.
returns → "content": [{type, text}], "isError": bool

Reason-able Action Spaces

What the RAS looks like in practice: multiple act() and reason() steps cooperating inside one bounded action space.

Code RAS (Python / TS)

Deterministic orchestration in scripts: branches, loops, retries, and validation happen in code, while `reason()` supplies bounded judgments. That gives the runtime Turing-complete deterministic control instead of probabilistic LLM-stepped control.

Source
build_analyzer.py
1
test_run = await act('bash', 'npm test -- --reporter json')
2
 
3
focus = await reason(
4
['Goal: pick the retry step.',
5
observation, 'Relevant context: latest CI run.',
6
'Constraints: return retry_cmd + reason only.'],
7
{"retry_cmd": "", "reason": ""},
8
)
9
 
10
retry_run = await act('bash', focus['data']['retry_cmd'])
11
decision = await reason(
12
['Goal: continue or escalate?',
13
retry_run['content'][0]['text'], focus['data']['reason'],
14
'Constraints: return action + reason only.'],
15
{"action": "continue", "reason": ""},
16
)
17
if decision['data']['action'] == 'escalate':
18
await act('notify', {'message': decision['data']['reason']})
19
print(decision['data']['reason'])
20
else:
21
await act('deploy', {'target': 'production'})
22
print('deployed')
Action Flow
flowchart

Bash RAS

Unix-style pipelines compose `reason` and `act` in a single action phase. Shell gives you deterministic, Turing-complete control flow, while the LLM stays confined to bounded local judgments.

$ act --manual | \
reason \
--prompt "Goal: find the tools needed to collect the most relevant API and documentation context for this task." \
--prompt - \
--prompt "Constraints: return only a JSON array of tool names. Prefer the smallest sufficient set." \
--structure '["tool_name"]' | \
jq -r '.data[]' | while read -r name; do act --manual "$name"; done
pipe |JSONpipe |acttool catalogreasonselect toolsjqunwrap namesactexpand defs
Data flowStructured JSONShell action

RAS as Harness

When the optional agent() extension is used, the RAS is the harness: agent() does delegated work inside it, and the RAS keeps that work explicit, bounded, and auditable.

Agent Harness Model

This is specifically the agent extension pattern: agent() runs delegated work inside the RAS, returns text and trajectory, reason() verifies those signals inside the RAS, and deterministic limits are enforced inside the RAS.

01Agent Extension

Delegated agent work

When the optional agent() extension is present, the RAS can host delegated agent work inside one bounded action space instead of turning that delegation into a separate top-level architecture.

02Local Check

Post-agent verification

In this pattern, reason() is not acting as an agent. It checks both text and trajectory returned by agent(), extracts the signal that matters, and turns it into structured control data.

03Runtime Control

Deterministic boundaries

Loops, max iterations, timeout, escalation, and stop conditions live in the runtime. That is what makes the RAS the harness for agent() rather than just another prompt wrapper.

This harness framing belongs to the optional agent() extension. The point is not that reason() is agent-related by itself, but that once agent()is introduced, the RAS becomes the harness that contains delegated work, verification, and escalation. See Agent Interface Extension. For related harness terminology in long-running agent systems, see Harness design for long-running apps.