Skip to content

Reasoning

The ask ... using step is how machines think. It sends a task to a reasoning provider (typically an LLM), receives structured output, and records the entire interaction in the behavioral ledger. This chapter covers everything beyond the basics: provider selection, system prompts, tool use, temperature control, and testing strategies.

Choosing a provider and model

The using parameter takes a provider:model string:

ask classify, using: "anthropic:claude-sonnet-4-6"
ask summarize, using: "openai:gpt-4.1"
ask translate, using: "google:gemini-2.5-flash"
ask local_classify, using: "ollama:llama3"
ProviderPrefixCommon models
Anthropicanthropic:claude-sonnet-4-6, claude-haiku-4-5
OpenAIopenai:gpt-4.1, gpt-4.1-mini
Googlegoogle:gemini-2.5-pro, gemini-2.5-flash
Ollamaollama:llama3, mistral, codellama
Groqgroq:llama-3.3-70b

If you omit using, the cell’s default model is used.

Structured output with returns

The returns block defines the exact shape of the model’s response. The runtime instructs the model to produce these fields and parses the response:

ask extract, using: "anthropic:claude-sonnet-4-6"
with task "Extract contact information from this text.\n\nText: ${input.text}"
returns
name as text
email as text
phone as text
company as text

You can use all the same types as accepts: text, number, boolean, list, map, list of text.

System prompts with role

with role sets the model’s persona. Use it to constrain behavior, set expertise, or establish a communication style:

ask analyze, using: "anthropic:claude-sonnet-4-6"
with role "You are a financial compliance officer. Flag any transaction that exceeds regulatory thresholds. Be specific about which regulation applies."
with task "Review this transaction.\n\nAmount: ${input.amount}\nType: ${input.type}\nCounterparty: ${input.counterparty}"
returns
compliant as boolean
flags as list
applicable_regulation as text

Task interpolation

Data goes directly into the with task string using ${expr}. There is no separate context block:

ask respond, using: "anthropic:claude-sonnet-4-6"
with task "Answer this question about our product.\n\nQuestion: ${input.question}\nRelevant docs:\n${steps.search.results.map(r => r.content).join('\n---\n')}\nCustomer tier: ${input.tier}"
returns
answer as text
confidence as text

Tool use

Give the model tools it can call during reasoning:

ask research, using: "anthropic:claude-sonnet-4-6"
with task "Research this company and provide a summary with revenue data"
with tools ["web_search", "read_url"]
returns
summary as text
revenue as number
sources as list

Tools declared in with tools are governed. Each tool call goes through the governance interpreter, is checked against permissions, and is recorded in the behavioral ledger.

Temperature and token limits

Control the model’s behavior with additional options:

ask creative_write, using: "anthropic:claude-sonnet-4-6"
with task "Write a tagline for this product: ${input.product_name}"
with temperature 1.2
with max_tokens 200
returns
tagline as text
alternatives as list of text

Lower temperature (closer to 0.0) produces more deterministic output. Higher temperature produces more varied, creative output.

Testing with assuming

Every ask step should have an assuming block. This provides mock values for test and simulate mode:

ask classify, using: "anthropic:claude-sonnet-4-6"
with task "Classify this ticket"
returns
category as text
priority as text
confidence as number
assuming
category: "technical"
priority: "medium"
confidence: 0.88

In test mode, the model is never called. assuming values are returned immediately. This means:

  • Tests are deterministic (same result every run)
  • Tests are fast (no network calls)
  • Tests are free (no API costs)
  • CI runs without API keys

Chaining multiple reasoning steps

You can chain ask steps. Each one can reference the output of previous steps:

machine deep_analysis
accepts
document as text, is required
implements
ask extract_facts, using: "anthropic:claude-haiku-4-5"
with task "Extract the key facts from this document.\n\n${input.document}"
returns
facts as list
assuming
facts: ["Fact 1", "Fact 2"]
ask synthesize, using: "anthropic:claude-sonnet-4-6"
with role "You are a research analyst. Synthesize facts into actionable insights."
with task "Given these facts, what are the key insights?\n\nFacts:\n${steps.extract_facts.facts.join('\n')}"
returns
insights as list
recommendation as text
assuming
insights: ["Insight 1"]
recommendation: "Proceed with caution"

Use a faster, cheaper model for extraction, and a more capable model for synthesis. Each call is independently governed and tracked.

Try it

Build a machine that takes a job description and a resume as input. Use two ask steps: one to extract key requirements from the job description, and another to evaluate the resume against those requirements. Return a match score and a list of gaps.

Next steps