# AI delivers the work. People where you want or need them.

You know work people pay for. Write it once, as one `Service()` and the brief you'd give a new hire.

`npx services.dev` writes this file and its brief, then serves them on localhost. Free to build: no account, key or card to start. On the free plan, services.dev earns only when your Service gets paid. [Run your first Service](https://services.dev/docs.md), or see a real Service, line by line, below.

```ts
// services/translation.ts
import { Service } from 'services.dev'

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

```md
<!-- services/translation.md -->
# Translation

The AI reads this brief on every job. Write it the way you'd brief someone new.

## How the work is done

- Translate the whole document into the language in `to`.

## What good looks like

- Every number, date and name exactly as written.

## Never

- Never summarize, and never leave a passage out.
```

```txt
$ npx services.dev
an agent ordered Translation at $49
job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged
  record  draft · ai | review · ai · pass
  ledger  +$49.00 · AI $0.84 · you $48.16
```

On localhost: AI and money are simulated until you wire them. $0.42 a call is an example. [Bring your model](https://services.dev/docs/service/ai.md#your-own-model)

```txt
lingua · AI delivers every job.
  site    http://localhost:8787/translation
  api     POST http://localhost:8787/jobs {"service":"translation"}
  key     sk_test_7Hq2 · a call with no key uses it, on localhost only
  mcp     http://localhost:8787/mcp · stdio: npx services.dev mcp
  cli     npx services.dev translation k=v …
  sdk     connect({ origin: 'http://localhost:8787' }).translation.order(input)
  docs    http://localhost:8787/llms.txt
  buyers  http://localhost:8787/portal
  you     http://localhost:8787/console
```

[See the API this file generated](https://services.dev/docs/examples/lingua/api/order_translation.md)

```ts
// buy.ts
// A buyer that is software: it reads lingua's card, asks the price, orders when the price fits
// its budget, waits for delivery and accepts. Run it beside `npx services.dev dev`.
import { connect } from 'services.dev/agent'
import translation from './services/translation.ts'

const lingua = connect('http://localhost:8787', { budget: 100 })
const lease = { url: 'https://example.com/lease.pdf', name: 'lease.pdf' }

const job = await lingua.order(translation, { document: lease, to: 'fr-CA' })
if (!('done' in job)) throw new Error(job.type === 'OFFER' ? job.price.sentence : job.reason)

const done = await job.done()
if (done.status !== 'delivered') throw new Error(`${done.id} ${done.status}`)
console.log(`${done.id} · delivered · ${done.output.document.name}`)

await job.accept()
console.log(`${done.id} · accepted · spent $${lingua.spent} of $100`)
```

```txt
$ node buy.ts
job_7Hq2 · delivered · lease.fr-CA.pdf
job_7Hq2 · accepted · spent $49 of $100
```

- **4** lines you write
- **17** things you don’t build
- **7** lines to add a sworn signer
- **0.4 s** from an empty folder to a delivered job

- [incorporations.legal](https://incorporations.legal): Legal · Company formation, filed
- [monthend.finance](https://monthend.finance): Accounting · The month-end close
- [closers.deals](https://closers.deals): Sales · Human closers on your deal
- [research.delivery](https://research.delivery): Research · Cited desk research
- [gigs.claims](https://gigs.claims): Insurance · Adjuster sign-off on claim files
- [api.cleaning](https://api.cleaning): Facilities · Commercial cleaning work orders
- [verifies.email](https://verifies.email): Marketing · Email list verification
- amended.tax: Tax · Amended returns, preparer signs
- denials.services: Healthcare admin · Claim-denial rework and appeal
- queues.support: Support · Support queues, worked by AI
- pentesters.work: IT and security · Pen tests, signed reports
- showings.properties: Real estate · Property showings, staffed
- interviewers.expert: Recruiting · Structured hiring interviews
- retouchers.pics: Design · Image finishing by retouchers
- parcelaudit.bid: Logistics · Parcel refund recovery

## 17 things you don't build

You know the work. You shouldn't have to build the plumbing to sell it. Your brand is on every surface, and your buyers never see services.dev. Here is what you don't build, and what prints in its place.

### 1. Describe the work

one file, as check reads it: `services/translation.ts · 4 lines · $49 per job, within 48 hours, charged on delivery.`

| You'd build | What printed instead |
|---|---|
| A model, prompted | `"deliver": [{"step":"draft","by":"ai","brief":"services/translation.md"}]` |
| A workflow engine | `record  draft · ai \| review · ai · pass` |
| A review step | `"review": "adversarial"` |
| Revisions | `npx services.dev send-back job_7Hq2 "Keep the defined terms in English."`<br>`sent back · buyer \| draft · ai · redo \| review · ai · pass` |
| Payments | `ledger  +$49.00 · AI $0.84 · you $48.16` |

### 2. Place people

one more line: `human: 'always',`

| You'd build | What printed instead |
|---|---|
| A review queue | `people       http://localhost:8787/people` |
| A hold on delivery | `job_7Hq2 · waiting · on approval · $49.00 held` |
| Payouts | `Certified Translation · you earn $60.00 of each $189 job` |
| Approval stats | `Translation: a person approved 1 of 1 job unchanged. next: try human: 'risky', or delete the line.` |

### 3. Sell it everywhere

one command: `$ npx services.dev`

| You'd build | What printed instead |
|---|---|
| A site | `site    http://localhost:8787/translation` |
| An API | `api     POST http://localhost:8787/jobs {"service":"translation"}` |
| An MCP server | `mcp     http://localhost:8787/mcp · stdio: npx services.dev mcp` |
| A CLI | `cli     npx services.dev translation k=v …` |
| An SDK | `sdk     connect({ origin: 'http://localhost:8787' }).translation.order(input)` |
| Docs for agents | `docs    http://localhost:8787/llms.txt` |
| A customer portal | `buyers  http://localhost:8787/portal` |
| An owner console | `you     http://localhost:8787/console` |

## One job, three apps

Your buyer tracks the job and you watch the margin. Place a reviewer, and they get the third app. One file makes all three.

| App | Path | job_7Hq2 |
|---|---|---|
| Customer portal | `/jobs/job_7Hq2` | `job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged` |
| Delivery portal | `/people` | `job_7Hq2 · waiting · on approval · $49.00 held` |
| Owner console | `/owner` | `job_7Hq2 · accepted · document.fr-CA.pdf · $49.00 final` |

[job_7Hq2 at every state, in every app](https://services.dev/docs/apps.md)

## Draw the line

AI delivers every job by default. It's your name on each one, so you choose where a person looks, and when to stop. Start wherever you trust the work. When people stop changing anything, the console moves you down a rung, then says delete the line. [Where you want a person](https://services.dev/docs/people.md#where-you-want-a-person)

| Your file | check prints | The buyer sees |
|---|---|---|
| (left out) | AI delivers every job. | `job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged` |
| `human: 'risky',` | A person approves the jobs the review flags, before delivery. | `job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged` |
| `human: { sample: 0.1 },` | A person checks one job in ten. The sample falls as send-backs stay rare. | `job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged` |
| `human: 'always',` | A person approves every job before delivery. | `job_7Hq2 · waiting · on approval · $49.00 held` |

With `human: 'always'`, job_7Hq2 waits in the delivery portal at `/people`: `job_7Hq2 · waiting · on approval · $49.00 held`. Approve sends it on: `job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged`. Then the owner console reads: Translation: a person approved 1 of 1 job unchanged. next: try human: 'risky', or delete the line.

## Work that needs a license

Name the credential and where it applies. Change those two words and it's your profession. The signer's name, credential and date are stamped into the work before it's hashed, so the act is theirs, and your brand runs everything around it.

```ts
// services/certified-translation.ts
  human: { sign: 'sworn-translator', in: 'country', before: 'certify' },
```

Your editor refuses a signer it can't route:

```txt
input: { document: 'file' }, output: { document: 'file' }, human: { sign: 'notary', in: 'document' }, price: 49
  ✗ Type '"document"' is not assignable to type '"✗ add a jurisdiction input to route a signer"'.
deliver: { draft: 'ai', certify: 'ai' }, human: { sign: 'notary', before: 'certfy' }, price: 49
  ✗ Type '"certfy"' is not assignable to type '"certify" | "delivery" | "draft" | undefined'. Did you mean '"certify"'?
```

The same line for a patent agent at [api.lawyer](https://services.dev/docs/examples/legal.md), `human: { sign: 'patent-agent', in: 'USPTO', before: 'file' },`, or an enrolled agent at [apis.tax](https://services.dev/docs/examples/tax.md), `human: { sign: 'enrolled-agent', in: 'US', before: 'efile' },`.

```txt
$ npx services.dev check
services/certified-translation.ts · 7 lines · $189 per job, within 3 days, charged on delivery.
  who     A sworn translator in the job's country signs before the certify step.
  steps   translate · Translation → review · ai · adversarial · then a person signs → certify · ai
  ledger  +$189.00 · AI $0.84 (example) · your Translation $49.00 · sworn translator $60.00 · you $79.16
  margin  at least $81.40 a job (43%) with your Translation · a job that stops costs you at most $107.60
  apps    customer portal · delivery portal · owner console
```

`job_9Kc4 · waiting · on signature · $189.00 held`, then a sworn translator signs in `/sworn-translators`: `job_9Kc4 · delivered · birth-certificate.fr.pdf · certificate.pdf · $189.00 charged`. A key that tries gets 403 `needs_a_person`: A person approves and signs, in the app. A key or a tool never can. [Who signs, and how they're placed](https://services.dev/docs/people.md)

## Work that takes years

Some work never ends: a return every year, a deadline the world sets. A clock runs the steps; the subject keeps the facts between jobs.

```ts
// apis.tax · services/tax-plan.ts
annual: { order: annualReturn, each: 'tax_year', at: '1mo after end', catch_up: 'open' },
estimate: { order: estimate, each: 'quarter', at: '10d before pay', when: sub => sub.input.entity === 'C corp' },
price: { usd: 2_400, every: 'year', includes: { 'annual-return': 1, 'information-returns': 25, estimate: 4, question: 12, 'notice-response': 2 } },
```

```txt
job_4Tx2 · delivered · workpapers-2025.txt · return.txt · $1,800.00 charged
$ npx services.dev tick 1y --test-clock tc_7Hq4
  2027-02-01 14:00:00  sbn_7Hq2  schedule annual → job_4Tx3 annual-return · period 2026 · $0.00 · allowance 1 of 1
  2027-02-01 14:00:00  job_4Tx3  ask organizer · signs@example.test · 8 items from 2025 (job_4Tx2) · 6 answered · 1 waived · 1 open (books)
  2027-04-05 13:00:00  sbn_7Hq2  schedule estimate → job_4Tx4 estimate · period 2027-Q1 · $0.00 · allowance 1 of 4
  2027-04-12 13:00:00  job_4Tx3  clock file · moved 2027-04-15 → 2027-10-15 · US, US-NY · US-NJ 2027-05-17 → 2027-11-15 · US-CA → 2027-11-15, automatic · each by its own rule · clock pay unmoved, still 2027-04-15
```

[A year, and the next](https://services.dev/docs/examples/tax/years.md)

## Every way a Service earns

Every job's split prints before you sell it.

| How it earns | The price line | One job | You keep | If it stops (costs you at most) |
|---|---|---|---|---|
| Per job (Translation) | `price: 49,` | `+$49.00 · AI $0.84 · you $48.16` | $48.16 | $9.80 |
| An upgrade to a person (Store Listing) | `price: { usd: 29, approved: 79, payout: 40 },` | `+$79.00 · AI $0.84 (example) · person $40.00 · you $38.16 · approved` | $38.16 | $55.80 |
| A signer, paid per job (Certified Translation) | `price: { usd: 189, payout: 60, within: '3d' },` | `+$189.00 · AI $0.84 · your Translation $49.00 · sworn translator $60.00 · you $79.16` | $79.16 | $107.60 |
| A share to a person (Interpreted Call) | `price: { usd: 150, payout: '70%' },` | `+$150.00 · AI $1.26 · interpreter $105.00 · you $43.74` | $43.74 | $135.00 |
| A share of the outcome (Claim Appeal) | `price: { usd: 99, share: '25%', of: 'recovery' },` | `+$99.00 at delivery · +$201.00 at outcome · AI $0.84 · you $299.16` | $299.16 | $19.80 |
| Not delivered, not charged (Translation · AI capped at 20%) | `job_7Hq2 · canceled · ai_cap · $0` | `AI $9.24 · you −$9.24` | −$9.24 |  |
| A yearly plan, with allowances (Tax Plan) | `price: { usd: 2_400, every: 'year', includes: { 'annual-return': 1, 'information-returns': 25, estimate: 4, question: 12, 'notice-response': 2 } },` | `+$2,400.00 · AI $0.84 (example) · you $2,399.16` | $2,399.16 | |
| Charged when the filing lands (Provisional Patent) | `price: { usd: 199, self: 79, release: 'file', within: '5d' },` | `+$199.00 · AI $2.10 (example) · practitioner $150.00 (rail brand) · coverage $4.00 · you $42.90` | $42.90 | |
| A share on a win, and 1% to the referrer (Deal) | `lines: { referral: { share: '1%', of: 'closed_value', to: 'referrer', on: 'won' } } },` | `+$9,920.00 · closer $6,200.00 (share, from the seller) · referrer $620.00 (line, from the seller) · placement $25.00 · AI $10.80 · you $3,064.20` | $3,064.20 | |

A share needs money to share:

```txt
input: { denial: 'file' }, output: { appeal: 'file' }, price: { usd: 99, share: '25%', of: 'appeal' }
  ✗ Type '"appeal"' is not assignable to type '"✗ add a money output to share"'.
```

services.dev's line: a take on each paid job, smaller on higher plans, and nothing on a job that isn't charged. Free builds and sells your first Service; each plan above adds what the business grows into. [Plans and the take](https://services.dev/docs/money/plans.md)

[How a Service earns](https://services.dev/docs/money.md)

## Agents buy too

Agents can't hire by the hour; they buy finished jobs. Yours quotes, sells and delivers, and hands over a link where a person must act.

```txt
→ GET /.well-known/agents.json
← 200 · lingua · mcp http://localhost:8787/mcp
→ order_translation {document: document.pdf, to: "fr-CA", key: "lease-fr-CA"}
← OFFER · $49 per job, within 48 hours, charged on delivery.
  next: order_translation {document: document.pdf, to: "fr-CA", max_usd: 49, key: "lease-fr-CA"}
→ order_translation {document: document.pdf, to: "fr-CA", max_usd: 49, key: "lease-fr-CA"}
← job_7Hq2 · working · $49.00 held
→ get_job {id: "job_7Hq2", wait: 50}
← job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged
  stage: review · payment: charged $49
→ accept_job {id: "job_7Hq2"}
← job_7Hq2 · accepted · document.fr-CA.pdf · $49.00 final
```

The same file with `human: 'always'`, when a key asks to approve:

```txt
→ POST /jobs/job_7Hq2/approve
← 403
"code": "needs_a_person",
"reason": "A person approves and signs, in the app. A key or a tool never can.",
"do": "hand_to_person",
```

Where a person must act, no key can act for them.

[How agents order](https://services.dev/docs/api.md)

## Real Services, line by line

### api.lawyer: Provisional patent application

Signed by a registered practitioner. `services/provisional-patent.ts` · 24 lines in Service().

```ts
import { Service } from 'services.dev'
import { attorneys } from '../pools/attorneys.ts'
import rules from '../rules.ts'
import docketWatch from './docket-watch.ts'

// The practitioner comes from the attorneys Pool, and the rules reserve signing and filing. price.self
// lets the applicant sign and file it themselves, for $79. The practitioner who signs stays of record on the patent
// family; if their registration lapses, another practitioner covers it, then the brand. The docket watch keeps its dates.
export default Service({
  name: 'Provisional Patent Application',
  description: 'A provisional application, drafted, examined, filed.',
  input: {
    invention: 'file[]: a description, drawings, anything you have',
    applicant: 'party', inventors: 'party[]', entity_size: ['micro', 'small', 'large'],
  },
  output: { application: 'file', exam: 'file', application_number: 'text' },
  rules,
  roles: { practitioner: { pool: attorneys, pay: 150 } },
  deliver: {
    consent: { ask: 'applicant', to: 'consent', expires: '7d' },
    questions: { ask: 'applicant', to: 'answer', within: '3d' },
    draft: { by: 'ai', cite: 'source' },
    examine: { review: 'adversarial', lenses: ['eligibility', 'novelty', 'obviousness', 'written description'], rounds: 3, exhausted: 'second_look' },
    second_look: { by: 'practitioner', routed: true, est: '1h' },
    sign: { by: 'practitioner', stamp: true, est: '1h', checklist: ['the claims read on the disclosure', 'every inventor is named', 'a reasonable inquiry was made'] },
    file: { submit: 'https://filings.example.test/patent-office', to: 'USPTO', receipt: 'application_number', wait: '2d', rejected: 'draft' },
  },
  subject: {
    kind: 'patent family', key: 'application_number', steward: docketWatch,
    of_record: { role: 'practitioner', named_at: 'sign', custodian: ['practitioner', 'brand'] },
  },
  ends: { withdrawn: { charge: 'acts', by: 'client' }, referred_out: { charge: false } },
  price: { usd: 199, self: 79, release: 'file', within: '5d' },
})
```

api.lawyer, whole: six Services · one Pool of attorneys · one rules table. One job: a provisional leaves you $42.90 of $199, charged when the USPTO files it. patent.click and incorporations.legal sell the same Services under their own names. [Build one like it](https://services.dev/docs/start/shapes.md)

### apis.tax: Tax plan

Runs all year. `services/tax-plan.ts` · 18 lines in Service().

```ts
import { Service } from 'services.dev'
import amendedReturn from './amended-return.ts'
import annualReturn from './annual-return.ts'
import estimate from './estimate.ts'
import informationReturns from './information-returns.ts'
import noticeResponse from './notice-response.ts'
import question from './question.ts'

// The plan a business buys. Its year routes to small Services with their allowances: five days after each calendar
// year, its 1099s; a month after each tax year ends, that year's return, and for a client who joins mid-year any year
// still open; ten days before each quarterly payment, a C corp's estimate; a question or a notice when one comes; and an
// amendment, at its own price, when a figure a later year read is restated. Past an allowance, the next is offered.
export default Service({
  name: 'Tax Plan',
  description: 'A tax year.',
  input: {
    business: 'party', owner: 'party: the officer who signs', ein: 'text: such as 12-3456789',
    entity: ['C corp', 'S corp', 'partnership'], jurisdictions: 'jurisdiction[]: the federal return first, then each state, such as US, US-CA',
    books: 'url: a read-only link to the ledger, such as https://books.example/acme',
  },
  output: { letter: 'file: the year in one page' },
  subject: { kind: 'taxpayer', key: 'ein' },
  on: {
    schedule: {
      information: { order: informationReturns, each: 'year', at: '5d after end', catch_up: 'open' },
      annual: { order: annualReturn, each: 'tax_year', at: '1mo after end', catch_up: 'open' },
      estimate: { order: estimate, each: 'quarter', at: '10d before pay', when: sub => sub.input.entity === 'C corp' },
    },
    event: { 'question.asked': question, 'notice.received': noticeResponse, 'fact.restated': amendedReturn },
  },
  price: { usd: 2_400, every: 'year', includes: { 'annual-return': 1, 'information-returns': 25, estimate: 4, question: 12, 'notice-response': 2 } },
})
```

apis.tax, whole: ten Services · its own Pool of preparers and signers, accountants imported · a plan that orders the year. One job: a four-state return leaves you $1,693.32 of $1,800, charged when the IRS accepts it. [Build one like it](https://services.dev/docs/start/shapes.md)

### api.forsale: Deal

Paid only on a win. `services/deal.ts` · 42 lines in Service().

```ts
import { Service } from 'services.dev'
import { closers } from '../pools/closers.ts'

// A deal, worked from first touch to the account's payment. AI sources, qualifies, books, meets and negotiates.
// A warm reply sends the booking to a setter, paid once the meeting is held. A deal of $50,000 and up, a buying
// committee or a seller who asks sends the meeting to a closer, who keeps the deal to the end. An account that goes
// quiet sends the deal to a nurturer, and a revived deal returns to the step it left. The gate refuses a close below
// the seller's floor, from AI or a person. Won is proven by the account paying the seller's own invoice.
const setter = job => job.policy.setter === 'person' || (job.policy.setter === 'on_warm' && job.signals.warm)
const person = job => job.input.value >= job.policy.humans_from || job.signals.committee || job.signals.person

export default Service({
  name: 'Deal',
  description: 'A deal, worked to close.',
  input: {
    account: 'party', value: 'money: list value', motion: ['B2B', 'B2C', 'B2D', 'B2A'], offer: 'url',
    referrer: 'party?', expansion: 'boolean?' },
  output: {
    held: 'meeting', closed_value: 'money: the first 12 months the contract commits, over what the account already pays', billing: ['annual', 'monthly'], term: 'months?',
    contract: 'file?', pay_link: 'url', notes: 'text', lost: ['no_fit', 'price', 'timing', 'competitor', 'dark'] },
  policy: {
    floor: { word: 'number', default: 0.8, min: 0.1, max: 1, binds: 'merits', note: 'the least share of list a close may take' },
    humans_from: { word: 'money', default: 50_000, note: 'a closer takes deals at or above this value' },
    setter: { word: ['ai', 'on_warm', 'person'], default: 'on_warm', note: 'who books the meeting' },
    stall_days: { word: 'number', default: job => (job.input.motion === 'B2C' ? 7 : 14), min: 3, max: 90 },
  },
  roles: {
    setter: { pool: closers, pay: { usd: 250, on: 'meet.held' } },
    closer: { pool: closers, span: ['meet', 'propose', 'negotiate', 'close'], revive: { first_call: '24h' },
      pay: { share: '10%', of: 'closed_value', on: 'won', from: 'buyer' },
      talk: { as: 'client', mail: 'client_domain', calls: 'bridged' } },
    nurturer: { pool: closers, pay: 150 },
  },
  signals: {
    warm: job => job.record.replies > 0, committee: { inbound: true }, person: { inbound: true },
    gone_dark: { silent: job => `${job.policy.stall_days}d`, of: 'account', goto: 'nurture' } },
  deliver: {
    source: 'ai',
    qualify: { by: 'ai', next: job => (job.output.fit ? 'book' : 'lost') },
    book: { by: 'ai', escalate: { to: 'setter', when: setter } },
    meet: { by: 'ai', escalate: { to: 'closer', when: person }, when: job => job.input.motion !== 'B2A',
      guard: { held: (m, job) => m.attended(job.input.account) >= 10 || 'no one from the account stayed 10 minutes' } },
    propose: { by: 'ai' }, negotiate: { by: 'ai' },
    close: { by: 'ai', next: job => (job.output.closed_value ? 'won' : 'lost'),
      guard: { closed_value: (v, job) => v >= job.input.value * job.policy.floor || 'below the floor you set' } },
    nurture: { by: 'nurturer', routed: true, next: job => (job.output.revived ? job.record.interrupted : 'lost') },
  },
  ends: { won: { charge: true }, lost: { charge: false, by: ['client', 'brand'] } },
  outcome: { amount: 'closed_value', proof: 'payment', match: { customer: 'account', metadata: 'deal' },
    window: { bank: '60d', card: '120d' }, tail: '90d', due: '90d', collect: job => (job.output.billing === 'monthly' ? 'each' : 'first') },
  price: { usd: 0, share: '5%', of: 'closed_value', on: 'won', ai: 40,
    lines: { referral: { share: '1%', of: 'closed_value', to: 'referrer', on: 'won' } } },
})
```

api.forsale, whole: one Service · a Pool of setters, closers and nurturers · nothing charged on effort. One job: a $74,000 deal leaves you $3,388.66 of $11,100, charged when the payment lands. Its setters, closers and nurturers work on closers.deals, and keep all of their pay. [Build one like it](https://services.dev/docs/start/shapes.md)

And lingua, the four-line Service: translation (4 lines), store-listing (5 lines), translated-summary (6 lines), certified-translation (7 lines). ✓ ready to sell · 4 Services · AI delivers 3 alone · each keeps at least 43% of every job [See a real Service, line by line](https://services.dev/docs/examples.md)

## A services business, in a few lines

Software sold tools and left buyers the work. Services-as-Software sells the finished job.

Every month on plumbing is a month someone else sells your work as software. Write the Service, and stop selling hours.

```txt
$ npx services.dev init "Store Listing"
  wrote   services/store-listing.ts · services/store-listing.md
  kept    package.json · AGENTS.md
  next    npx services.dev dev
```

init writes AGENTS.md, so the agent in your editor knows the loop:

```md
# Agent instructions
- After every change, run `npx services.dev check --json` and fix each failure from its `doc_url`.
```

`npx services.dev init "<what you sell>"`, then [run your first Service](https://services.dev/docs.md), or [see the whole system](https://services.dev/docs/start/system.md).
