TL;DR: Pick your riskiest module (billing, auth, or entitlements). Write down what must happen, what must not happen, and the edge cases. Put it in a
.pbc.mdfile in your repo. That's it — you now have a behavior spec. This guide walks through the whole process.
Every other post on this blog explains why behavior specs matter. This one shows you how to write one.
You'll need: a code editor, 15 minutes, and one module in your product where an agent mistake would actually hurt.
Step 1: Pick the module
Don't try to contract your entire product. Start with the module where getting it wrong costs the most.
Good first candidates:
- Billing — grace periods, refund windows, proration, plan limits
- Auth — session handling, permission checks, account lockout
- Entitlements — what free users can and can't do, trial limits
- Onboarding — the flow that shapes first impressions
Pick one. For this tutorial, we'll use billing.
Step 2: Create the file
Create a file called billing.pbc.md in your repo. The .pbc.md extension is a convention — it's still plain Markdown. Put it wherever makes sense: the root, a docs/ folder, or alongside the code it describes.
Start with frontmatter:
---
id: billing
title: Billing & Subscriptions
context: billing
status: draft
updated: 2026-04-04
---
The status: draft is honest — you're writing this for the first time. It'll become trusted once your team has reviewed and confirmed the behaviors.
Step 3: Define the scope
Write a short section describing what this contract covers and what it doesn't. This prevents scope creep and tells readers (human and agent) where the boundaries are.
# Billing & Subscriptions
## Scope
- Subscription lifecycle (trial, active, past due, cancelled, expired)
- Payment failure and grace period behavior
- Plan limits and what happens when they're exceeded
## Non-goals
- Payment gateway API details (that's implementation)
- Invoice formatting (that's presentation)
- Tax calculation logic (that's a separate module)
Step 4: List your terms
If your module uses domain-specific language, define it. This eliminates ambiguity — the grace period means exactly this, not whatever someone infers from the code.
## Glossary
| Term | Definition |
| --- | --- |
| Grace period | The 14-day recovery window after a failed renewal payment. |
| Billing cycle | The recurring period (monthly or annual) between charges. |
| Plan limits | The monthly usage caps for a given subscription tier. |
Step 5: Write the behaviors
This is the core of the contract. For each behavior, write:
- Given — the preconditions (what must be true before this happens)
- When — the trigger (what kicks off this behavior)
- Then — the outcomes (what must happen)
Start with the happy path, then add failure cases and edge cases.
## Behaviors
### Automatic renewal
#### Given
- The subscription is active
- The current billing cycle ends today
- A valid payment method exists
#### When
The system processes the subscription for renewal.
#### Then
1. A charge is submitted to the payment processor
2. On success: subscription stays active, billing cycle advances
3. Plan limits reset for the new period
---
### Payment failure and grace period
#### Given
- The subscription is active
- A renewal charge fails
#### When
The payment processor reports a failed charge.
#### Then
1. Subscription moves to past_due status
2. User retains full access for 14 days (the grace period)
3. System retries the payment on days 1, 3, and 7
4. If payment succeeds during grace period: subscription returns to active
5. If grace period ends without payment: subscription moves to expired
#### Invariants
- Grace period is exactly 14 days — not configurable per plan
- No data deletion occurs during grace period
- User is notified on each retry attempt
#### Edge cases
- If user manually updates their payment method during grace period: immediate retry
- If user downgrades plan during grace period: grace period continues on the new plan
That's a behavior spec. It's readable by your team, your agents, and anyone who touches this code six months from now.
Step 6: Add structured blocks (optional but powerful)
Plain Markdown is already useful. But if you want tools and agents to parse the spec deterministically — not just read it as prose — you can add pbc:* fenced blocks.
These are YAML blocks inside Markdown code fences with a pbc: prefix. They look like code blocks to a Markdown renderer, but a PBC-aware tool can extract them as typed data.
For example, add a structured version of the glossary:
```pbc:glossary
- term: Grace period
definition: The 14-day recovery window after a failed renewal payment.
- term: Billing cycle
definition: The recurring period (monthly or annual) between charges.
- term: Plan limits
definition: The monthly usage caps for a given subscription tier.
```
And a structured version of a behavior:
```pbc:behavior
id: BIL-BHV-002
name: Payment failure and grace period
actor: billing_scheduler
description: When a renewal charge fails, the system enters a 14-day grace period with retries before expiring the subscription.
```
```pbc:preconditions
- The subscription is in active.
- A renewal charge fails.
```
```pbc:trigger
The payment processor reports a failed charge.
```
```pbc:outcomes
- Subscription moves to past_due.
- User retains full access for 14 days.
- System retries payment on days 1, 3, and 7.
- If payment succeeds: subscription returns to active.
- If grace period ends without payment: subscription moves to expired.
```
You don't have to add structured blocks for everything. Start with plain Markdown. Add pbc:* blocks to the behaviors that are most critical — the ones where you want a tool to be able to verify they're still honored.
Step 7: Point your agents at it
Add a line to your CLAUDE.md, AGENTS.md, or whatever instruction file your agents read:
Before modifying any billing, auth, or entitlement logic, read the relevant
`.pbc.md` file in this repo. Do not change behaviors marked as invariants
without explicit approval.
This is the bridge between your existing agent workflow and the behavior spec. The instruction file says "look here first." The behavior spec says "here's what the product promises."
Step 8: Review with your team
Share the .pbc.md file with your team. Ask two questions:
- Is this accurate? Does the spec match what the product actually does?
- Is anything missing? Are there behaviors or edge cases that should be captured?
When you and your team agree the spec is accurate, change status: draft to status: trusted.
That's it. You have a living behavior spec — your product truth — in your repo.
What you just built
In 15 minutes, you created an artifact that:
- Humans can read — plain Markdown, renders on GitHub, in any editor
- Agents can reference — structured enough to check decisions against before coding
- Tools can parse —
pbc:*blocks are deterministically extractable - Lives in your repo — version-controlled, diffable, evolves with your code
You didn't write documentation. You wrote product truth — a structured statement of what the product promises to do, explicit enough that both humans and agents can hold the code accountable to it.
Next steps
- Browse the full billing example in the PBC viewer to see what a complete behavior spec looks like
- Read the PBC spec for the full list of
pbc:*block types (states, actors, rules, config, events) - Add a second behavior spec for your auth or entitlements module
- If you want Stewie to extract candidate behaviors from your codebase automatically: request early access