---
title: "Your code as a step"
url: https://services.dev/docs/service/code
captured: [own-model.txt, service-check.txt, service-cite.txt, tax-check.txt]
---
# Your code as a step

URL: https://services.dev/docs/service/code

> A function can do the whole job or one step of it. It gets the input and the job, returns output, and can name the rule its calculation follows on the record.

A code step answers one question: which part of the work is a calculation you already know how to do?

## Smallest form

```ts title="services/paged-translation.ts"
    count: { by: async ({ document }) => ({ pages: Math.ceil((await document.text()).length / 1800) }), cite: 'a standard page: 1,800 characters' },
    translate: 'ai',
```

```bash
npx services.dev check
```

```txt title="magic values: none"
  steps   count · code · cites a standard page: 1,800 characters → translate · ai → review · ai · adversarial
```

## Every form

**On a work step**

| Key | Written | Left out | Does |
|---|---|---|---|
| `by` | `Doer` | required | Who proposes the output: `'ai'`, `'person'` or a role word, a URL, your function, or another of your Services. |
| `cite` | `'source' \| (string & {})` | none | 'source': every output field cites the input it rests on, and the review fails a field that doesn't. A string: the authority a calculation follows, recorded on the line. |

**In your code, on the job**

| Key | Written | Left out | Does |
|---|---|---|---|
| `input` | `Data` | required | The order's input, each file with a `text()` reader. |
| `ai` | `(instructions, ...files) => Promise<string>` | required | Calls the model with the Service's brief. Its cost is the ledger's AI cell. |
| `outcome` | `(won) => void` | required | Reports what a job won, for a share: `job.outcome({ recovery: 3000, evidence })`. |
| `output` | `Partial` | required | What committed steps returned. |
| `policy` | `PolicyValues` | required | The order's policy, every default filled. |
| `signals` | `{ <name>: boolean }` | required | The signals raised so far. |
| `feedback` | `string[]` | required | What the work was told to fix, oldest first: a review's flagged findings, a send-back's note, an outside system's rejection codes. The AI reads it on every redo. |

## The whole job

Make `deliver` a function and it does all the work, here with your own model. It returns the whole output, and the record prints `code` where it printed `ai`:

```ts title="services/translation.ts"
import { Service } from 'services.dev'
import { translate } from '../model.ts'

export default Service({
  name: 'Translation',
  input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
  output: { document: 'file' },
  deliver: async ({ document, to }) => ({ document: await translate(document, to) }),
  price: 49,
})
```

```bash
npx services.dev dev
```

```txt title="captured"
an agent ordered Translation at $49
job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged
  record  draft · code | review · ai · pass
  ledger  +$49.00 · AI $0.42 · you $48.58
```

The AI left in the ledger is its review.

## One step

As a step, a function is called with `(input, job)` and returns part of the output. The steps after it read what it returned on `job.output`, beside the order's `job.policy`, the raised `job.signals` and the `job.feedback` a redo reads: the last table in [Every form](#every-form). Each file input arrives with a `text()` reader.

## The rule it follows

`cite` puts the rule a calculation follows on its line in the record, so anyone replaying the job can check the arithmetic against it:

```bash
curl http://localhost:8787/owner/jobs/job_7Hq2   # the count step's line on the record
```

```json title="magic values: none"
{
  "type": "step.committed",
  "step": "count",
  "by": "code",
  "fields": [
    "pages"
  ],
  "cite": "a standard page: 1,800 characters"
}
```

## When your code says no

A code step proposes, like every doer, and [the gate](https://services.dev/docs/service/gate.md) commits it. Refused, your code would propose the same again, so the job stops. A step that throws stops the job, and the buyer pays $0.

Inside a function, `job.ai(instructions, ...files)` calls the same AI as `'ai'`, with the same brief.

## Seven surfaces

No call of its own: it changes what the job carries, on every surface that reads one.

[Operations](https://services.dev/docs/reference/operations.md) has every column of every row.

## Refusals

| Written | What TypeScript says |
|---|---|
| `deliver: async input => ({ document: input.document }), price: 49` | `Property 'recovery' is missing in type '{ document: InFile; }' but required in type '{ readonly document: FileRef; readonly recovery: number; }'.` |

## In the example brands

The lines that use it in the example brands, as their files write them, and what `check` read aloud for each file.

```ts title="tax · services/estimate.ts · 17 lines"
    record: { by: async (_, job) => ({ paid: job.output.amount }), when: job => decided(job) === 'pay it' },
```

```txt title="npx services.dev check · captured/tax-check.txt"
services/estimate.ts · 17 lines · $79 per job, within 48 hours, charged on delivery.
  steps   compute · code · cites prior-year safe harbor, cumulative by quarter → approve · owner · decide → review · ai · adversarial → pay · Treasury and states · one for each jurisdiction with an installment → record · code
```

[The tax example](https://services.dev/docs/examples/tax.md) runs every one of its files, captured.

---

- Up: [Service()](https://services.dev/docs/service.md)
- Previous: [One submission per element](https://services.dev/docs/service/each.md)
- Next: [Sourced output](https://services.dev/docs/service/sourced.md)
