Build software and operations Agents

Build coding, repository, monitoring, diagnosis, remediation, and incident-response Agents with governed evidence and effects.

Before you begin

Expose repositories, sandboxes, telemetry, deployment systems, and incident tools as separate governed Resources. Give read and write operations different Policy actions. Decide whether the Agent may only propose a patch or mitigation, may execute it after approval, or may execute a narrow idempotent remediation automatically. Keep secrets behind Resource boundaries and treat repository and log content as untrusted.

Why coding Agents use a ReAct loop

A coding Agent cannot reliably plan every action before seeing the repository. Reading a file changes what it should inspect next; applying a patch determines which checks matter; a compiler or test failure becomes evidence for the next correction. ReAct makes that dependency explicit by repeating reason → act through a Tool → observe the durable result until the Agent has enough evidence to finish.

Constal's react() implementation in @constal/std is more than a prompt convention. It supplies a durable state machine, preserves the Tool transcript in content-addressed storage, reconstructs a bounded context window for each turn, consumes operator steering exactly once, and requires the model to call an explicit final Tool. Every repository or sandbox action still crosses its normal Resource, Policy, effect, recovery, and journal boundary.

That combination makes the loop suitable for multi-turn work without making it unbounded. maxTurns, budget Policy, the window option, optional transcript folding, Tool schemas, and Resource Policy constrain how long the Agent can continue and what each iteration may do. A failed check is therefore an input to another durable turn—not permission to bypass the sandbox or expand authority.

Steps

  1. Project only the required repository and sandbox operations as model-facing Tools. Keep inspection read-only and classify edits, commands, and deployment operations by their real effects.
  2. Configure react() with coding instructions, the offered Tool names, and a bounded context window. Bind a CAS Resource so long transcripts can be stored and resumed.
  3. Let each Tool receipt drive the next turn: inspect before editing, run targeted checks after editing, and use actual failures as correction evidence.
  4. Require approval before higher-risk deployment or remediation. End only through the explicit final Tool, then commit the resulting patch reference and verification summary.
  5. Use subtasks for genuinely independent investigations, not for every file, command, or test.
ts
import { agent, type Tool } from "@constal/sdk";
import { react, type ReactState } from "@constal/std";

const sandboxExec: Tool = {
  name: "sandbox_exec",
  version: "1",
  description: "Inspect or modify the repository and run checks in the governed sandbox.",
  schema: {
    type: "object", required: ["cmd"], additionalProperties: false,
    properties: { cmd: { type: "string" }, args: { type: "array", items: { type: "string" } } },
  },
  maxEffect: "reconcilable",
  needs: [{ binding: "sandbox-pool", kind: "sandbox-pool", ops: ["createSandbox", "exec"] }],
  async run(args, ctx) {
    const pool = ctx.sandboxPool(ctx.resources["sandbox-pool"]!);
    const sandbox = await pool.createSandbox(ctx.run.agent.crn, ctx.run.session);
    return sandbox.exec(args);
  },
};

const behavior = react({
  system: [
    "Work iteratively on the requested coding task.",
    "Inspect relevant files before editing and make the smallest correct change.",
    "Run targeted checks and treat their actual output as evidence.",
    "Never claim a check passed unless its Tool result says so.",
    "Call final only with the patch reference, checks run, and remaining risks.",
  ].join(" "),
  tools: ["sandbox_exec"],
  window: 48,
});

export default agent<ReactState>({
  id: "coding-agent",
  version: "1.0.0",
  model: "model",
  mode: behavior.mode,
  tools: { sandbox_exec: sandboxExec, ...behavior.tools },
  init: behavior.init,
  async step(state, ctx) {
    const next = await behavior.step!(state, ctx);
    if (next.done) {
      await ctx.commit({ kind: "coding-result", result: next.state.final });
    }
    return next;
  },
  output: behavior.output,
});

The deployment binds model, sandbox-pool, and cas, enables both sandbox_exec and final, and sets finite maxTurns and maxRunMicroUsd limits. react() does not create infrastructure authority: the Tool opens the bound SandboxPool, idempotently creates the Agent/Session workspace, and invokes its pinned exec operation. Transcript chunks use the bound CAS Resource.

A monitoring Agent can use the same loop with metrics, traces, logs, and topology Tools. An incident Agent may spawn bounded diagnostic subtasks and then await an operator before mitigation. A safe automatic remediator should expose a tiny idempotent operation with a probe, not general shell access disguised as a Tool.

Verify

Test malicious repository text, missing diagnostics, failing checks, stale deployment state, duplicate events, uncertain writes, context-window rollover, and a restart between ReAct iterations. Confirm the Agent resumes the same transcript, incorporates each Tool result before choosing its next action, exits only through final, and distinguishes proposal, attempted action, verified action, and committed outcome. The journal must identify each Resource, operation, Policy decision, and effect result. No prompt instruction should expand the Agent’s accepted authority.

Next steps

Read Build a ReAct Agent with the library, Resources and Tools, Identity, Policy, and authority, Analytics, and Multi-Agent and long-horizon systems.