5 min readCJ Brewer

Prompt or process? Why operational agents need to be declarative

A prompt is a useful starting point for an agent, but operational work needs a durable, reviewable system with declared state, permissions, approvals, and failure paths.

swirlsagentsworkflowsdeclarativeoperations

At 9:00 a.m., an agent reviews an inbox, identifies three customers who need a response, and updates their records. The CRM request times out after the provider accepts it. On retry, the agent writes the same notes again and produces a second set of follow-ups. Nobody can tell which run changed what, or whether either draft should be sent.

That is not a failure of language-model judgment. It is what happens when a prompt is asked to carry the responsibilities of a process.

Most agent work begins with a Markdown file, because a clear instruction, relevant context, and a desired outcome offer an effective way to explore whether an agent can add value to a business process.

A team might write, “Every morning, review this inbox, identify customers who need a response, update the CRM, and prepare follow-ups.” That instruction can reveal useful behavior quickly, but it cannot carry the full operational responsibility once the agent begins handling customer information, changing systems of record, and shaping work for a team.

The important question is therefore whether the agent remains a prompt or has become a process.

A process has inputs that matter and outputs other systems and people rely on. It holds state, takes actions, needs permissions, and fails in ways somebody must understand and recover from. A human might need to approve a consequential decision before it ships.

Those requirements distinguish an impressive agent demo from operational software.

#Prompts describe intent, while processes define responsibility

A prompt describes the outcome you want from an agent, while an operational system defines the conditions under which the agent can pursue that outcome.

An inbox-triage agent requires a clear boundary around the inboxes it can access, the messages it can read, the information it can store, the CRM records it can update, and the communications it can prepare or send. A production system also needs an answer for duplicate runs, interrupted execution, unavailable services, conflicting records, and decisions that require review.

These are the everyday realities of operating software inside a business, and they deserve to exist as an explicit, reviewable definition rather than as assumptions embedded in a prompt.

Declarative agents make that definition concrete by expressing the trigger, inputs, outputs, tools, permissions, workflow steps, database state, approval points, and failure paths in a form that teams can version, review, validate, deploy, and audit. In Swirls, those declarations are not conventions around a model call: the runtime executes them durably, scopes connections and typed actions, preserves state, and records every step.

#Declarative agents bring proven engineering discipline to agentic systems

The movement toward declarative agents follows a familiar and successful engineering pattern.

SQL made data operations explicit, infrastructure-as-code made infrastructure explicit, and versioned application code made software changes reviewable and repeatable. These systems replaced hidden scripts and tribal knowledge with definitions that teams could inspect, test, deploy, and evolve together.

Operational agents deserve the same discipline because their reasoning layer may vary while their operational environment must remain bounded and understandable. Their inputs can follow declared schemas, their outputs can follow structured contracts, their authority can be scoped to specific tools and data, their state can be durable, and their consequential actions can flow through human approval.

This structure gives teams a system with a knowable operational shape, even when a language model contributes useful judgment inside the process.

#What the inbox prompt becomes in practice

The original instruction contains several responsibilities. In a Swirls file, each is a small declaration that a team can inspect independently. The node declarations below live inside the triage_customer_inbox workflow named by the trigger.

#1. Decide when the process runs

schedule morning_inbox {
  label: "Morning customer inbox triage"
  cron: "0 9 * * 1-5"
  timezone: "America/New_York"
}

trigger triage_on_weekday_morning {
  schedule:morning_inbox -> triage_customer_inbox
}

This is the process's clock: it runs at 9:00 a.m. on weekdays in the chosen timezone. The trigger binds that schedule to one named workflow, rather than leaving timing as an instruction the model has to remember.

#2. Declare the inbox it may read

connection customer_inbox {
  label: "Customer inbox"
  provider: microsoft
}

This gives the workflow an OAuth-backed connection to one Microsoft inbox. It does not grant a general ability to access email; the connection is a named, reviewable boundary that must be configured for the project.

#3. Read only the messages the process needs

node read_inbox {
  type: integration
  label: "Read unread customer messages"
  connection: customer_inbox
  action: microsoft_list_folder_messages
  params: @ts {
    return {
      folder_id: "inbox",
      "$filter": "isRead eq false",
      "$top": 25,
      "$select": "id,subject,bodyPreview,from,receivedDateTime,isRead",
    }
  }
}

The microsoft_list_folder_messages action is a typed integration from the Swirls catalog. This is the concrete inbox boundary: unread messages only, capped at 25, through the connection declared above. The action supplies a known input and output shape instead of passing an unbounded email session into the model.

#4. Bound the model's judgment

node decide {
  type: ai
  label: "Identify customers who need a response"
  kind: object
  model: "google/gemini-2.5-flash"
  schema: @json {
    { "type": "object", "required": ["decisions"],
      "properties": { "decisions": { "type": "array" } } }
  }
  prompt: @ts {
    return (
      "Review these unread inbox messages and return one decision for each customer message.\n\n" +
      JSON.stringify(context.nodes.read_inbox.output.value)
    )
  }
}

The model decides whether a response is needed and prepares a draft, but it must return a defined record for each message. The production schema can require the message ID, customer email, CRM note, and draft; the important boundary is that the model cannot silently invent a new action, change the schedule, or write directly to a system of record.

#5. Choose where durable CRM state lives

If the business already uses a CRM, the workflow can update it through a declared connection and typed actions. For example, an Attio connection makes the existing customer record the system of record:

connection customer_crm {
  label: "Customer CRM"
  provider: attio
}

If the workflow needs to own its operational state instead, it can declare a managed database. This is useful when the process needs records that do not belong in the team's existing CRM, such as a durable triage log and draft history.

database customer_ops {
  label: "Customer operations"
  schema: @prisma {
    model Customer {
      email    String @id
      lastNote String?
      triages  InboxTriage[]
    }

    model InboxTriage {
      messageId     String @id
      customerEmail String
      needsResponse Boolean
      crmNote       String
      followUpDraft String?
      customer      Customer @relation(fields: [customerEmail], references: [email])
    }
  }
}

The database declaration defines the durable operational record: a customer, the note written about the interaction, and a triage record identified by the email message ID. A repeat run can update the existing record instead of creating a duplicate action.

#6. Gate consequential state changes with review

node update_customer_ops {
  type: database
  label: "Update customer operations after review"
  database: customer_ops
  operation: transaction
  review: {
    enabled: true
    title: "Approve customer record updates"
    description: "Review the proposed notes and follow-up drafts before recording them."
  }
  run: @ts {
    const decision = context.nodes.decide.output.decisions[0]
    return context.db.customer_ops.inboxTriage.upsert({
      where: { messageId: decision.messageId },
      update: { needsResponse: decision.needsResponse, crmNote: decision.crmNote },
      create: decision,
    })
  }
}

The review declaration pauses before the customer-record changes occur and presents the notes and follow-up drafts to a person. The transaction makes each approved update an explicit, auditable action; it is not an incidental side effect of the model call. Swirls checkpoints the workflow around that pause, so an interruption does not turn the approval step into an ambiguous retry.

Finally, the workflow connects the declared steps in their intended order:

flow {
  root -> read_inbox
  read_inbox -> decide
  decide -> update_customer_ops
}

Taken together, these declarations answer the questions the original instruction leaves open: when the work runs, which inbox it can read, what durable fields it records, how a duplicate message is handled, and where a person reviews the proposed changes. The prompt contributes judgment, but the file defines responsibility.

#Start with a prompt, then promote the work into a system

Markdown remains an excellent starting point when a team is exploring an idea, learning a process, or testing whether AI judgment can improve a particular task.

The work should become a declarative system when it starts handling customer information, changing records, coordinating people, spending money, sending communications, or becoming a dependency in a recurring business process. At that point, the agent needs the same operational contract that every other important system in the business already carries.

Businesses will increasingly run their day-to-day operations through agents, and the teams that succeed will build agents whose autonomy has an explicit, reviewable shape.

Swirls is the platform that makes those declarations run reliably in production: it executes and checkpoints the workflow, preserves its state, scopes its connections and typed actions, pauses for review, and records what happened.

Prompt or process? Operational builders should ask that question early, because it determines whether an agent remains an experiment or becomes software the business can rely on.

Ship your first business process with Swirls today.