# Automating the notice

URL: /code/learn/automating-the-notice · Id: `page:code/learn/automating-the-notice`

> Tutorial 8 of 12 writes the Workflow that sends each renewal notice at 60 days, then moves the test clock to watch it run.

A [Workflow](/business/nouns/workflow) is one file that holds its description, its code and its test. Leaseline declares a `Lease` [Noun](/business/nouns/noun), and its renewal notice goes out every morning without anyone asking.

## What you build
You write the Workflow behind the renewal notice: each day, every active lease that ends in 60 days gets `Lease.notify`. Then you advance the test clock and read the [Events](/business/nouns/event) it wrote.

## Steps
1. To write the Workflow, create its document under the renewals [Process](/business/nouns/process):

   ~~~mdx title="workflows/renewals/notice-at-60-days.mdx"
   ---
   stakes: low
   ---
   ## Send the notice at 60 days {#notice-at-60-days}

   Each morning, every active Lease that ends in 60 days gets its renewal notice.

   ```ts
   every.day(async ($) => {
     const endsOn = new Date(Date.now() + 60 * 86_400_000).toISOString().slice(0, 10)
     for await (const lease of $.Lease.list({ where: `status = active and endsOn = ${endsOn}` }).all())
       await $.step(lease.$id, () => $.Lease.notify({ lease: lease.$id }))
   })
   ```

   ```ts test
   import { expect, run } from 'startup-builder/test'
   const { calls } = await run({}, { Lease: { list: () => [{ $id: 'lease_4loEed1JG4', status: 'active' }], notify: () => ({}) } })
   expect(calls).toEqual(['Lease.list', 'Lease.notify'])
   ```
   ~~~

   Each `$.step` is durable: a retry resumes after the last finished lease.

2. To run a day in test, move the clock:

   ```bash
   npx startup-builder clock advance --by 1d
   ```

3. To read what ran, list the latest Events:

   ```bash
   npx startup-builder show /events --fields 'seq,name,at'
   ```

## Result
The Workflow runs every morning, notifies each lease at 60 days and writes `Lease.notified` for each. From 2026-10-01 to 2026-10-22, Leaseline's ran 22 times and sent 14 notices. Checkpoint `leaseline@ch08` (status `planned`) adds `workflows/renewals/`.

## Next steps
- [Tutorial 9](/code/learn/seating-the-agent) gives the residents' replies to the [Success Manager](/agents/customer/success-manager) agent.
- [Workflows](/code/file-conventions/workflows): triggers, schedules and steps.