Skip to content

Durable Goal Execution

Mesh.execute_goal() turns one natural-language objective into durable, capability-addressed work. Redis holds the source goal, obligations, revisions, claims and outputs; peers claim work independently. Planning does not create a manager agent and the node that publishes a plan has no execution authority.

This API is different from the other two ways to run work:

API Use it when Who defines the steps
agent.execute_goal() One AutoAgent should run its own Plan, Execute, Evaluate loop That AutoAgent
mesh.workflow() Your application already knows the DAG Your Python code
mesh.execute_goal() The goal should be compiled into distributed, capability-addressed work A temporary planning lease
flowchart TB
    Source["Source goal and obligations"] --> Plan["Temporary planning lease"]
    Plan --> DAG["Capability-addressed DAG"]
    DAG --> Claims["Independent peer claims"]
    Claims --> Attempts["Immutable attempts and evidence"]
    Attempts --> Truth{"Current obligations satisfied?"}
    Truth -->|Yes| Final["Current-revision final response"]
    Truth -->|Actionable gap| Delta["Append selective revision"]
    Delta --> Claims
    Truth -->|No valid remediation| Blocked["Durable blocked settlement"]

Source-grounded obligations

The planner receives immutable source blocks derived from user-authored goal lines and selects a source_ref for each semantic obligation. JarvisCore then hydrates the durable source_quote itself from the selected block. The model never has to reproduce exact source text, and unknown references fail closed.

For a one-line goal, source-1 identifies the complete goal. Multi-line goals also expose each non-empty line as its own block and source-all for requirements that span lines. The model still decides what the obligations mean; the compiler owns only their exact provenance binding. Existing persisted ledgers continue to carry validated source_quote values.

Define capability authority

Every participating agent declares capability names. For provider work, add a capability contract so planning knows which effects and systems that capability may use:

from jarviscore import AutoAgent, Mesh


class RevenueOperations(AutoAgent):
    role = "revenue_operations"
    capabilities = ["pipeline_inspection"]
    capability_descriptions = {
        "pipeline_inspection": "Inspect and reconcile CRM pipeline state.",
    }
    capability_contracts = {
        "pipeline_inspection": {
            "effects": ["read", "propose"],
            "systems": ["hubspot"],
        },
    }


mesh = Mesh(config={
    "mesh_response_capability": "action_briefing",
    "execution_budget": {
        "max_seconds": 900,
        "max_tokens": 240_000,
        "max_epochs_per_step": 8,
    },
})
mesh.add(RevenueOperations)

Effects are read, propose, write, notify, destructive or final_response. A write, notify or destructive step names exactly one authorized system. The claiming peer still decides which atom or provider call to use.

At least one started node needs an agent with an LLM for initial planning and reconciliation decisions. A pure CustomAgent node can execute published work, but it does not gain an LLM planner automatically.

Execute and inspect a goal

await mesh.start()

result = await mesh.execute_goal(
    "Inspect the active opportunity and prepare a decision brief.",
    workflow_id="opportunity-2026-09-11",
    context={"tenant_id": "acme"},
)

print(result["status"])            # completed, waiting, failed or cancelled
print(result["result_summary"])    # the answer
print(result["output"])            # what the final step delivered
print(result["evidence"])          # every step's tool observations

output and evidence are the same as run_task() returns. A failed goal carries error, the failing step's reason. When a step is paused for a person, status is waiting and result["waiting"] names the step, why it waits and its metadata. steps still holds every step's record for anything more detailed.

Caller context is copied without private keys or execution authority. The framework derives capability, effect and systems from the published step and injects them into the claiming agent's task context.

Source-backed products should set workspace_required=True. Source resolution and snapshot integrity validation then complete before the goal is registered or the planner sees it. Explicit structured context is accepted from APIs and CLIs; message-only clients rely on the Mesh's provider-constrained source preflight. Missing source identity, unavailable adapters and invalid snapshots fail the request instead of producing a source-less DAG.

Give the planner the Mesh's method

The source goal says what the user wants. The capability catalog says what the available peers can do. A product can also declare mesh_planning_brief to tell the generic planner what kind of team it is compiling work for:

mesh = Mesh(config={
    "mesh_planning_brief": """This Mesh reviews shipped services. For broad
    review work, establish an executed baseline, investigate falsifiable risks,
    verify findings independently, and report tested coverage and residual risk.
    A negative result requires substantial executed coverage. Explicit user
    scope and do-not-modify constraints override the normal method.""",
})

The brief informs DAG drafting, independent audit, repair, amendment and reconciliation. It is deliberately excluded from obligation extraction: product method cannot manufacture a user request. Source constraints and approval boundaries always outrank the normal method, and the capability catalog remains the authority boundary.

A useful brief answers five questions:

  1. On what occasion is this Mesh used?
  2. What method does it normally apply to broad work?
  3. How should it adapt when an intermediate hypothesis or path fails?
  4. What evidence makes the work complete, including a valid negative result?
  5. Which explicit user constraints narrow or override the normal method?

Describe outcomes and evidence standards, not a fixed list of agent instances, tools or provider calls. The planner still constructs the task-specific DAG and peers still claim capabilities directly.

Run a validated plan template

When a product already knows the DAG for a kind of question, it can pass that plan as plan_template and skip the planning call. The Mesh validates the template against the same rules as a planned DAG (known capabilities, effects and systems the capabilities authorize, dependencies, obligation coverage, a final response step) and publishes it:

result = await mesh.execute_goal(
    goal,
    workflow_id="question-42",
    plan_template={
        "obligations": [{
            "id": "o1", "description": "Answer from evidence", "source_quote": goal,
        }],
        "steps": [{
            "id": "research", "capability": "research", "effect": "read",
            "systems": [], "task": "Find evidence",
            "success_criterion": "Evidence exists",
            "expected_findings": ["evidence"], "depends_on": [], "covers": [],
        }, {
            "id": "analyse", "capability": "analysis", "effect": "read",
            "systems": [], "task": "Analyse the evidence",
            "success_criterion": "Analysis uses evidence",
            "expected_findings": ["analysis"], "depends_on": ["research"],
            "covers": ["o1"],
        }],
    },
)

A template accepts only goal, obligations, steps and revision (which must be 1), and its goal must equal the source goal. If it fails validation, the ledger records plan_template_rejected with the reason and the goal is planned normally. The published template is the workflow's initial plan: amendments, resume and reconciliation work as for a planned DAG. Re-running the same workflow id with the same goal and context resumes it; a different goal is rejected.

submit_goal() accepts plan_template too.

Task context received by agents

Both AutoAgent.execute_task() and CustomAgent.execute_task() receive the same distributed context:

Key Meaning
objective Exact immutable source goal
workflow_plan Goal, obligation ledger and all revisioned step definitions
previous_step_results Durable artifacts from direct depends_on producers; all workflow artifacts for a final response
previous_step_interpretations Semantic assessments from dependencies
workflow_id, step_id Durable execution identity
capability, effect, systems Authority declared by the published step
execution_budget Shared workflow budget
workflow_evidence Final-response snapshot of artifact IDs, interpretations, states and obligations; full artifacts remain in previous_step_results

For normal steps, transitive ancestry establishes execution order but does not implicitly forward artifacts. A step that needs outputs from multiple earlier producers must list each producer directly in depends_on. This keeps evidence flow explicit and prevents unrelated ancestral payloads from inflating context. A dependency contributes only the artifact promised by its own task and success criterion; a summary, ranking or approval does not implicitly relay the evidence it consumed. Steps needing both original evidence and a transformed decision must depend directly on both producers.

The independent planning audit may express a missing artifact edge as a typed add_dependencies correction. The auditor still decides which evidence the target step needs; JarvisCore validates and applies those exact edges, rejects unknown or cyclic references, and audits the corrected DAG again. Explanatory audit prose is never parsed into graph behavior.

Capabilities may additionally declare artifact_types and requires_artifact_types. JarvisCore deterministically closes direct edges from consumers to every matching producer, including immutable producers during a reconciliation revision. Products that assemble nested evidence can declare artifact_reference_paths; agents then select artifact_ref locations while JarvisCore copies the exact validated values before product validation.

When interpreted domain work leaves source obligations unresolved, response authority remains pending while reconciliation amends or settles that revision. An amended response step supersedes pending response steps from prior revisions, so users receive one answer from current obligation state.

An exhausted execution epoch may continue from its durable checkpoint, up to max_epochs_per_step. For source-backed work, JarvisCore also exports the partial same-step WorkspaceDelta and reapplies it before the next epoch. Tool history, mutation receipts, and file state therefore advance together. A request larger than an entire epoch is terminal because starting another identical epoch cannot make it fit.

A run that stops without an accepted answer, whether its last epoch ran out or its answer was refused, carries what it established in progress: the agent's working notes and its last refused answer with the reason, marked "verified": false. A step that reaches max_epochs_per_step keeps that progress in its EXECUTION_EPOCH_LIMIT_REACHED record, so the replanner and the final answer can report what was found and what remains.

Kernel coroutine tools execute on the asyncio event loop. Synchronous tools run in a worker thread with the current workflow context propagated, so a blocking provider or sandbox call cannot starve distributed claim renewal. Redis fencing still rejects results from a claimant that genuinely loses ownership.

Completion is evidence-derived

DONE is an agent proposal to evaluate the current durable state. It is not a state transition by itself. Normal turns and budget-exhaustion landing turns use the same completion evaluator. Rejected completion preserves tool history, thoughts, failures and work-product state; actionable lease exhaustion continues in a fresh bounded epoch rather than becoming a human wait. When repeated completion proposals leave the same actionable gate unsatisfied, that boundary also checkpoints the same state; the next epoch receives the gate evidence as its critical error instead of restarting an equivalent dispatch.

Products may declare execution_contract.required_tool_groups. Each group lists equivalent tools, and durable history must contain at least one invocation from every group before completion is eligible. The gate reports observed tools and missing groups; it does not decide domain truth or choose the next action. Changing result wording without changing the observed evidence or performing a new tool action is not progress and cannot reset the no-progress boundary.

Every tool invocation receives an immutable, workflow-scoped tool_receipt_id in Kernel state. Command observations in final JSON must carry that receipt ID. JarvisCore replaces model-authored command, exit-code, output, timestamp and duration fields with the authoritative runtime receipt before accepting DONE. Direct dependencies carry already-grounded receipts to downstream synthesis. Missing and unknown receipts fail closed and keep the same agent state active. Products can use the public CommandObservation model without implementing evidence matching or retry logic.

Other cited tool results carry observed_tool_result: the original tool input, output, status and error. The agent's authored conclusion remains separate from that observation. Evaluators reason from the actual query, scope, period and coverage rather than treating a real citation as proof of the conclusion. Unfinished dependency records retain their status and progress in follow-up and final-response context; they are not reduced to an empty output.

workspace_write and hash-guarded workspace_edit use the same contract through the public WorkspaceMutation model. JarvisCore binds path, hash, byte size and executable state to the tool receipt, then reconciles cited local mutations against the final exported WorkspaceDelta. A mutation that was reverted, overwritten, or produced no net change cannot support an applied claim. Receipts created before a bounded epoch continuation remain valid only while their exact file content remains in the cumulative same-step workspace. Product normalization and JSON repair run before this final Mesh-owned integrity check, so they cannot invent receipt evidence.

Workspace deltas are cumulative from the immutable source snapshot. When a step directly depends on both an ancestor and its descendant, the descendant delta is the maximal branch and already contains the ancestor's accepted changes. Mesh materialization applies only maximal branches, while incompatible parallel sibling branches still fail with WorkspaceDeltaConflict.

Existing agents do not need to change. A successful result without an interpretation is reduced from execution status: a completed attempt satisfies the obligations covered by that step.

Optional semantic interpretations

Return an interpretation when domain evidence can distinguish "the attempt completed" from "the source requirement is satisfied". This is how an agent can hold or reject its assigned path without teaching JarvisCore domain rules.

async def execute_task(self, task):
    artifact = await self.inspect_pipeline(task)
    plan = task["context"]["workflow_plan"]
    step = next(item for item in plan["steps"] if item["id"] == task["id"])
    covered = list(step["covers"])

    if artifact["stage"] is None:
        interpretation = {
            "meaning": "The deal exists, but its current stage is not verified.",
            "satisfied_requirements": [],
            "unmet_requirements": covered,
            "evidence_refs": [artifact["record_id"]],
            "verdict": "unsatisfied",
            "decision": "hold",
        }
    else:
        interpretation = {
            "meaning": "The current deal stage was read from the CRM.",
            "satisfied_requirements": covered,
            "unmet_requirements": [],
            "evidence_refs": [artifact["record_id"]],
            "verdict": "satisfied",
            "decision": "proceed",
        }

    return {
        "status": "success",
        "output": artifact,
        "interpretation": interpretation,
    }

satisfied_requirements and unmet_requirements contain the stable obligation IDs from the current step's covers list, not paraphrased descriptions. Assess each covered ID exactly once. Recommended verdicts are satisfied, partial and unsatisfied; recommended decisions are proceed, hold and reject.

A framework-owned final-response step has covers=[]. It presents current workflow truth and cannot satisfy source obligations. When multiple steps in one dependency path mention the same obligation, only terminal domain work retains coverage; ancestor steps remain evidence for that terminal judgment.

Step dependencies use dependency_policy="satisfied" by default. Redis decides whether dependencies are execution-ready; the recipient peer decides whether a completed dependency's semantic uncertainty materially prevents its task. A planner may set dependency_policy="terminal_evidence" only for work explicitly intended to diagnose or remediate a failed or blocked attempt. Final-response steps always receive terminal evidence so they can explain blocked and incomplete goals.

Current obligation truth

Attempts are immutable execution history. The obligation projection records which attempts currently represent each source requirement:

flowchart LR
    R1["Revision 1<br/>inspect_deal<br/>unresolved"]
    R2["Revision 2<br/>inspect_deal_by_id<br/>satisfied"]
    R1 -->|"superseded for this obligation"| R2
    R1 -.-> Audit["Retained audit history"]
    R2 --> Current["Current obligation evidence"]

The revision 1 output remains available for audit. Revision 2 supersedes it only for the obligation IDs covered by the new step. Satisfied obligations not named by the delta retain their current source attempt and are not rerun.

Automatic reconciliation starts only after the current revision is terminal, an unresolved obligation has semantic evidence, an LLM planner is available and the revision budget permits another attempt. The planner may append remediation or settle the remaining goal as blocked. It cannot rewrite the source obligation ledger or mutate earlier attempts.

Mesh.replan_goal() uses the same append-only mechanism for explicit continuation. Call it only while obligations remain unresolved:

result = await mesh.replan_goal(
    "opportunity-2026-09-11",
    reason="A direct CRM record-read capability is now available.",
)

Read terminal status correctly

The result reports three independent facts:

Field Values Question answered
status completed, failed, waiting, cancelled Did the current revision execute?
obligation_status satisfied, blocked, incomplete Is the source goal fulfilled?
response_status completed, failed, waiting, not_required Was the current user-facing response produced?

Do not infer goal truth from status alone. For example, provider actions may be complete while response synthesis fails:

{
    "status": "failed",
    "obligation_status": "satisfied",
    "response_status": "failed",
}

Agent Desk renders completed as Execution finished. The result separately renders Goal satisfied, Goal blocked or Goal incomplete from obligation_status.

revision identifies the current plan. steps retains attempts from every revision; filter with step["plan_revision"] == result["revision"] when you need only current execution. result_summary is selected from the current revision's final response.

Waiting, cancellation and shutdown

Resume a waiting step with the same workflow and step identity:

result = await mesh.resume_goal(
    workflow_id,
    step_id,
    context={"human_response": "approved"},
)

The final response can be written while a step waits, so the person sees what the goal is waiting for. Resuming the step reopens that response: it is written again from the resumed work, and a response still being written from the paused state is discarded when it finishes. The resumed result's result_summary therefore describes what actually happened after the decision.

Cancellation is durable. It fences future claims and prevents an expired executor from committing after cancellation:

mesh.cancel_goal(workflow_id, reason="Request withdrawn")

Cancelling the coroutine running execute_goal() also cancels the durable workflow before re-raising CancelledError.

Schedules and event triggers

submit_goal() registers a goal and returns its workflow id without waiting. Schedules use it to start work later, on an interval, or when something happens, and to wake a waiting step:

# Every morning, for one person
mesh.schedule_goal(
    "Tell me what in my inbox needs me today",
    every_seconds=86_400,
    context={"owner_id": "ada"},
)

# When the source says so
mesh.schedule_goal("Triage this email", event="email.received", context={"owner_id": "ada"})
await mesh.emit_event("email.received", {"message_id": "m-7"}, event_id="m-7")

# Follow up in three days
mesh.schedule_wake(workflow_id, step_id, at=time.time() + 3 * 86_400)

Schedules live in Redis and a scheduler task on every started Mesh fires them, polling every schedule_poll_seconds (default 5). Each occurrence has a deterministic workflow id, so nodes sharing Redis start it once. Give emit_event() the id the source already has and a redelivered event starts nothing new. A recurring schedule that missed moments while nothing ran fires once and continues from now. The started goal's context carries schedule (and event for triggers) so agents know why they are running. mesh.cancel_schedule(schedule_id) removes a schedule.

Deployment rules

  • Redis is required for Mesh.execute_goal(), resume, replan and cancellation.
  • Use stable workflow_id values for retry and observation.
  • Run compatible framework versions on every node that can claim the same DAG.
  • Bound reconciliation with mesh_max_reconciliation_revisions and the shared execution_budget.
  • Configure mesh_response_capability only when a peer owns final_response authority.