How We Scope an AI Agent Before Quoting a Fixed Price: The Week-One Spec
Agents 10 min2026-06-03

How We Scope an AI Agent Before Quoting a Fixed Price: The Week-One Spec

Fixed-price agent work is only honest when the state space is bounded first. Here is the week-one spec we price against: four variables, the deliverable list, the three tiers, and the LangGraph and Pydantic pattern that makes the number hold.

An agent proposal that says "the AI will handle it" for a flat retainer has not been scoped. It has been guessed. The guess surfaces later, as a loop that burns a weekend of API credit and dies on an unhandled rate-limit error. Nobody can say what the system was allowed to do in the first place.

We quote agent builds at a fixed price because we spend the first week turning the request into a specification narrow enough to engineer against. The output of that week is a number you can sign, not a range you can argue about. What follows is the spec itself: the four variables we measure, the deliverable list, the tiers, and the code pattern that makes the price hold.

Why agents break ordinary scoping

In a normal web application, effort scales with endpoints. The tenth endpoint costs about what the first did. The state space is finite, and each endpoint behaves the same way every time.

Agents do not behave this way. An agent with two tools is markedly more complex than an agent with one. The model now has to choose between them, pass state between them, and recover when either fails. Add a third tool and you have a routing problem on top of a reasoning problem.

</>View technical implementation · عرض التفاصيل التقنية
Traditional API: input → validation → business logic → DB write (deterministic)
Agent:           input → planner → tool selection → tool call → reflection → state update → write

Every arrow in the second line is a place the system can loop, drift, or invent arguments. Without hard bounds, the planner can call itself until the context window runs out or the bill does. That is where "spaghetti" agents come from: prompt patches bolted on in production to catch edge cases nobody scoped.

Fixed-price work is only honest if the state space is bounded before the first commit. Bounding it is the whole job of week one. Before that week starts, we also ask whether the task needs an agent at all. n8n handles more business automation than vendors admit, and a fixed sequence of steps belongs there, not in a bespoke agent.

The four variables we measure before quoting

Before any price goes on paper, we audit the workflow against four variables. Each maps to a cost: tokens per request, failure rate under load, and the hours we have to budget for guardrails and evaluation.

1. Graph size. We draw the workflow as a state graph. Each state is a node: extracting data, validating a payload, calling an external API, waiting for a person. Each transition is an edge. A linear three-node flow is cheap. A graph with cycles for self-correction and conditional routing is not. If the graph does not fit on one page, it is a multi-agent system, and we price it as one.

2. Tool schema strictness. Searching a vector store takes a string. Writing a journal entry into an ERP takes a strict schema with validation, idempotency keys and dry-run support. The second kind of tool needs far more code around it. The model will produce malformed arguments sooner or later, and the integration has to reject them cleanly rather than corrupt downstream data.

3. State payload size. If the agent only passes a transaction ID between steps, state is trivial. If it carries a structured medical record or a multi-page invoice through a dozen reasoning steps, state drift becomes the main failure mode. The model drops a field, renames a key, or quietly coerces a type. These workflows need typed state schemas and explicit reducers, not a loose dictionary.

4. Evaluation surface. You cannot ship an agent you cannot evaluate. Before quoting, we estimate how many golden examples are needed to cover the critical paths: the inputs where a wrong answer is expensive. That number drives both the build cost and the regression suite we hand over. The golden dataset and CI gate are described step by step in the evals post.

What the week-one deliverable contains

The spec we produce in week one is the document the fixed price is quoted against. It is short, concrete and specific to your workflow. Every section exists because leaving it vague is how projects go over budget.

  • ▸State graph diagram. Every node, every edge, every termination condition. If a cycle exists, its maximum iteration count is written next to it.
  • ▸Tool inventory. For each tool: the exact schema, whether it reads or writes, which system it touches, and whether failures are retryable or terminal.
  • ▸State schema. The typed structure the graph carries between nodes, with the fields each node may read and write.
  • ▸Guardrail list. Hard limits: maximum steps per run, maximum tokens per step, timeout per external call, maximum cost per request. Written as numbers, not adjectives.
  • ▸Human-in-the-loop handoff points. The exact conditions under which the agent stops and asks for a person, and the channel it uses. Where the handoff points go, and what the reviewer needs to see, is a design decision we make with you.
  • ▸Evaluation set. The golden examples the agent must pass before we ship, and the metrics we score against.
  • ▸Deployment target. Where it runs, how it is monitored, who owns the alerts.

That document is what we price. If you want to add a tool after sign-off, we re-price the difference. If we underestimated the hours, the overrun is ours. The spec also fixes the build order. For a product rather than an internal agent, the eight-week sequence shows what you hold at the end of each phase.

The tiers we quote

We sort incoming work into three tiers by the first three variables. All three sit inside the published band of $8K to $45K for workflow automation agents. What drives the build price within that band is its own post.

TierNodesToolsStateTypical shape
Linear agentUp to 31 or 2Simple key-valueClassify, look up, write one record
Orchestrated graph4 to 103 to 5Typed state with reducersConditional routing, self-correction loops, one approval gate
Multi-agent systemMore than 106 or moreHierarchical or shared storeSeveral specialised agents and a coordinator

Guardrail and evaluation hours grow with each tier. We state them in the spec as planning assumptions, not promises, and they are the part of the estimate most often missing from other quotes. Suppose a quote arrives for an agent that writes into ten production systems, with no human review step and a very low price. You are buying a demo. The spec above is how you can tell.

TIP

Never let an agent write directly to a production database. Route every write through a validation layer with schema checks, idempotency keys and rate limits. Treat the agent's output the way you would treat input from any untrusted client.

The structural guardrails that make the price hold

The code below is the pattern that lets us commit to a fixed number. It uses LangGraph for the state machine and Pydantic for tool-argument validation. A hard recursion limit means a confused planner cannot bankrupt you one request at a time.

</>View technical implementation · عرض التفاصيل التقنية
import os
from typing import Annotated, Dict, Any, List, Literal
from typing_extensions import TypedDict
from pydantic import BaseModel, Field
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from litellm import completion

class State(TypedDict):
    messages: Annotated[List[Dict[str, Any]], add_messages]
    user_id: int
    tax_rate: float
    execution_errors: List[str]

class TaxCalculationSchema(BaseModel):
    user_id: int
    country_code: str = Field(..., description="ISO 3166-1 alpha-2 code, e.g. 'AE'")

def calculate_tax(payload: TaxCalculationSchema) -> Dict[str, Any]:
    if payload.country_code == "AE":
        return {"tax_rate": 0.05, "status": "success"}
    return {"tax_rate": 0.15, "status": "success"}

def call_model(state: State) -> Dict[str, Any]:
    # LiteLLM lets us swap model families without touching the graph.
    response = completion(
        model=os.environ["AGENT_MODEL"],
        messages=state["messages"],
        tools=[{
            "type": "function",
            "function": {
                "name": "calculate_tax",
                "description": "Calculate tax rate based on user location.",
                "parameters": TaxCalculationSchema.model_json_schema(),
            },
        }],
        tool_choice="auto",
    )
    return {"messages": [response.choices[0].message]}

def execute_tools(state: State) -> Dict[str, Any]:
    last = state["messages"][-1]
    results, errors = [], []
    for call in last.get("tool_calls", []):
        if call["function"]["name"] != "calculate_tax":
            continue
        try:
            args = TaxCalculationSchema.model_validate_json(call["function"]["arguments"])
            result = calculate_tax(args)
            results.append({
                "role": "tool", "tool_call_id": call["id"],
                "name": "calculate_tax", "content": str(result),
            })
        except Exception as e:
            errors.append(str(e))
            results.append({
                "role": "tool", "tool_call_id": call["id"],
                "name": "calculate_tax", "content": f"Error: {e}",
            })
    return {"messages": results, "execution_errors": errors}

def route(state: State) -> Literal["tools", "__end__"]:
    return "tools" if state["messages"][-1].get("tool_calls") else "__end__"

workflow = StateGraph(State)
workflow.add_node("agent", call_model)
workflow.add_node("tools", execute_tools)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", route)
workflow.add_edge("tools", "agent")

app = workflow.compile()

# recursion_limit is the hard financial boundary per request.
config = {"recursion_limit": 10}

The pattern does three things. The recursion limit caps steps per request; once a run exceeds it, LangGraph raises GraphRecursionError, as the graph API docs describe. Pydantic validation on every tool call means a malformed argument fails fast instead of corrupting a downstream system. And routing is explicit: the agent may only move to states we drew in week one.

None of this is novel. All of it is skipped in the demos that break in production.

Why we design for handoff, not full autonomy

Getting an agent to handle the common path of a well-scoped workflow on its own is a solved problem. Chasing full autonomy is where budgets detonate. The last fraction is adversarial inputs, dialect edge cases, uploaded documents with embedded prompt injections, and the long tail nobody can enumerate in advance.

So we do not price for full autonomy. Every system we build has an explicit off-ramp. Execution halts and the task goes to a person in three cases. The model's confidence drops below a configured threshold. The state hits a transition we did not draw. A tool fails more than once. The handoff carries the full state payload, so the human sees exactly what the agent saw.

The LangGraph production patterns post covers the mechanics. The business point is simple. We can commit to a fixed price because we are not promising to solve every edge case. We are promising a system that handles the common path well, flags the uncommon path cleanly, and never silently guesses.

Frequently asked questions

Why fixed price instead of hourly? Hourly aligns incentives badly. If we misread the complexity, you pay for our learning. Fixed price moves that risk onto us, which is only fair if we have earned the right to carry it. The week-one spec is how we earn it.

What happens when a model provider changes something and the agent breaks? Every model call goes through LiteLLM. Swapping between Claude, GPT, Mistral, or a locally hosted Qwen or Llama model is then a configuration change. The regression suite from week one tells us whether a new model passes before it goes live. If it does not, we stay on the old one.

How do you keep the agent from doing something harmful? The reasoning layer and the execution layer are kept apart. The agent never holds raw database credentials or open-ended API access. It produces JSON payloads that go to a gateway, and the gateway enforces schema and business rules. A refund above a set amount needs approval; writes to protected tables are blocked. The agent can be wrong; the gateway makes "wrong" cheap.

→ n8n vs Custom AI Agents: How to Choose Before You Spend the Money → How Much Does It Cost to Build an AI Agent System? → Buying AI Engineering as a Non-Technical Founder: Three Questions and One Cost Formula
Workflow automation agents →
Agents that write into your systems behind approval gates and logs. $8K to $45K fixed, 6 to 8 weeks, full source code handed over.

This week, take one workflow you want automated and draw its state graph on a single page. Mark every node, every tool it calls and every cycle. Then count them and see which tier the graph lands in. If it does not fit on the page, you have learned the most expensive fact about the project before anyone has quoted it.

Related services