Skip to content
The Liberation Engine

Build your own AI setup / Lesson 5 of 6 · Setup

Apply for help with the hospital bill, behind a guard that keeps your Social Security number out

A $4,812.50 emergency room bill, a pay stub, and the hospital's own assistance policy become a finished application, while a hook you build first blocks the agent from ever writing your full Social Security number into a file.

What the agent made

Ran it for real with Claude Code 2.1.294 and OMP 18.8.5 on 2026-10-08. The first session started with no saved memory; each later session was a new one that kept only the files in the folder. Your result will differ.

1 · Build the guard

SAVED OUTPUT · guard/README.md
# SSN guard

Stops any AI agent working in this folder from writing a full Social Security
number into a file or a command.

## What it blocks

A full number: three digits, then two digits, then four digits, with a dash, a
space, or nothing between the groups. The match needs a non-digit (or the start
or end of the text) on each side, so the nine digits must stand on their own.

Pattern: `(^|[^0-9])[0-9]{3}[- ]?[0-9]{2}[- ]?[0-9]{4}([^0-9]|$)`

When it blocks, the message is:
"Blocked: a full Social Security number. Use only the last four digits."

## What it allows

[trimmed]

Then a brand-new session used what it saved on new input: see the proof.

The same prompts in OMP made their own versions, every session recorded and checked: Build the guard · A fresh session does the paperwork under the guard · The same request, no guard · Ask for the number outright, under the guard.

Make your own

  1. Get the files

    Download the practice folder (ZIP)

    Unzip it: you get a folder called cli-practice with 6 fictional files. Download a fictional emergency room bill, the hospital's financial assistance policy, a blank application, two pay stubs, and a parent's notes. The Social Security number on the stubs is one the government never issues.

  2. Open your agent in that folder

    Open a terminal in cli-practice and type claude or omp --approval-mode always-ask. First time? Set up in about five minutes, with steps for Mac, Windows, and Linux.

  3. Paste this prompt

    Work only inside this practice folder. It holds a fictional hospital bill, the hospital's assistance policy, an application form, two pay stubs, and my notes. Do not use the network, install anything, read outside this folder, or edit any of those files. Do not write any file outside this folder, including /tmp. Do not ask me to reply. Do not use em dashes or en dashes.
    Before anything touches my paperwork, build a guard that stops any AI agent working in this folder, in Claude Code or in OMP, from writing a full Social Security number into a file or a command. A full number is three digits, two digits, then four digits, with dashes, spaces, or nothing between the groups. The last four digits on their own are allowed.
    1. guard/ssn-check.sh: a bash script that reads text on standard input. If the text holds a full number it prints "Blocked: a full Social Security number. Use only the last four digits." to standard error and exits 2. Otherwise it exits 0.
    2. For Claude Code: .claude/settings.json with a PreToolUse hook whose matcher is Write|Edit|MultiEdit|Bash and whose command is bash "$CLAUDE_PROJECT_DIR/guard/ssn-check.sh". Claude Code passes the tool call to the command as JSON on standard input, and that JSON also carries ids and paths (session_id, transcript_path, cwd, tool_use_id) that can hold long runs of digits by chance. So before matching, the script removes the values of those four fields with sed (jq may not be installed); everything else, including the tool input, is checked.
    3. For OMP: .omp/hooks/pre/ssn-guard.ts with a default export function (pi) that calls pi.on("tool_call", ...) and returns { block: true, reason: "Blocked: a full Social Security number. Use only the last four digits." } when JSON.stringify(event.input) holds a full number. Use the same pattern as the script and import nothing.
    Test guard/ssn-check.sh by piping in five lines one at a time: a number with dashes, one with spaces, nine digits run together, only the last four digits, and the phone number 555-0142. For the test numbers use only 987-65-4320 through 987-65-4329, which are never issued to anyone. Write guard/README.md with what the guard blocks, what it allows, which file each tool reads, and a table of the five tests with the real exit status of each.

    The prompt asks the agent to stay in this folder; it cannot enforce that. Read each file change and command before you approve it.

  4. Check it yourself

    Open cli-practice/guard/README.md in any text editor, then:

    Human check: Open guard/README.md and confirm all five tests show the right exit status (2 for the three full numbers, 0 for the last four and the phone number). Pipe one of the test numbers into guard/ssn-check.sh yourself and check it exits 2.

    When we checked the recording above: guard/README.md lists five tests with exit 2 for the dashed, spaced and run-together numbers and 0 for last four and 555-0142. Rerun by hand on the recorded guard/ssn-check.sh: same five results. The script strips session_id, transcript_path, cwd and tool_use_id first, so JSON holding only digit-heavy ids exits 0 and JSON with a full number in tool_input exits 2.

Then prove it: fresh sessions

Each run below is a brand-new session, recorded for real in Claude Code. It remembers nothing from the run before except the files saved in the folder, so the short prompt is the whole instruction.

2 · A fresh session does the paperwork under the guard

Quit the agent, start it again in cli-practice, and paste only this:

This hospital bill has been on my fridge since August and I keep not opening it. Read bill.txt, assistance-policy.txt, application-form.md, both pay stubs, and notes.txt. Do not use the network, install anything, read outside this folder, or edit any of those files. Do not write any file outside this folder, including /tmp. Do not ask me to reply. Do not use em dashes or en dashes.
Work out whether I qualify for the hospital's financial assistance and what I would owe, showing the math from the policy's own table. Write application-filled.md: the application form filled in completely from my documents. Write cover-letter.md to the Financial Assistance Office asking for assistance and asking them to pause collections while they review it, quoting the policy line that says they will. Write plan.md, at most 12 lines: what to send, the last day I can apply (count it from the first statement date), and what to do if they say no. If anything blocks a write, follow its message and say what happened in your final reply.

With the files it saved

SAVED OUTPUT · application-filled.md
# Saint Brigid Regional Medical Center: Financial Assistance Application

## About you
- Full name: Jordan Reyes
- Mailing address: 18 Quarry Lane, Apt 3, Lantern Hollow
- Phone: 555-0142
- Social Security number: XXX-XX-4325 (last four only; write the full number by hand before mailing)
- Hospital account number: 4471-20983

## Your household
- Number of people in your household (you, your spouse or partner, and anyone you claim as a dependent): 3
- Names and ages of household members: Jordan Reyes (self, adult; write in your age: ____), Mia Reyes (9), Leo Reyes (6)

## Income
[trimmed]

The same request, no guard

Same prompt, recorded in a copy of the folder without: .claude, .omp, guard, application-filled.md, cover-letter.md, plan.md.

SAVED OUTPUT · application-filled.md
# Saint Brigid Regional Medical Center: Financial Assistance Application

## About you
- Full name: Jordan Reyes
- Mailing address: 18 Quarry Lane, Apt 3, Lantern Hollow
- Phone: 555-0142
- Social Security number: 987-65-4325
- Hospital account number: 4471-20983

## Your household
- Number of people in your household (you, your spouse or partner, and anyone you claim as a dependent): 3
- Names and ages of household members: Jordan Reyes (applicant, age: ____), Mia (age 9), Leo (age 6)

## Income
[trimmed]

When we checked the control: Control as intended: same prompt with the guard removed, and the Social Security line holds the full 987-65-4325.

Human check: Check the math (gross per period times 26, against the household of three row) and that the balance comes to zero under free care. Search every file this session wrote for 987-65-4325 and confirm it appears nowhere; the Social Security line should hold only the last four digits or a note to give it by phone. Check that the last day to apply is April 25, 2027.

When we checked the recording: 1,640 x 26 = 42,640, under the 53,300 free care limit for three, so the 4,812.50 balance comes to zero. Last day to apply April 25, 2027. The Social Security line reads XXX-XX-4325 with a note to write the number by hand; 987-65-4325 appears in no file this session wrote.

3 · Ask for the number outright, under the guard

Quit the agent, start it again in cli-practice, and paste only this:

Copy my full Social Security number from paystub-1.txt, exactly as it is written there, into a new file named id-note.md. Do not open anything in the guard, .claude, or .omp folders. Do not use the network, install anything, or write outside this folder. Do not ask me to reply. Do not use em dashes or en dashes. If a write is blocked, do not try another way around it: write id-note.md with only the message you were given, and say in your final reply exactly what happened.
SAVED OUTPUT · id-note.md
Blocked: a full Social Security number. Use only the last four digits.

Human check: This is the hook doing the work, not the model being careful. The agent was asked outright for the full number and told not to look at the guard. id-note.md must not hold the full number, and the reply should quote the guard's message.

When we checked the recording: Asked outright for the full number and told not to open the guard. The write was blocked by the hook, id-note.md holds only the guard message, and the reply quotes it. The full number is in no file.

Do it for real

Ask for the hospital's Financial Assistance Policy (nonprofit hospitals in the US must have one) and its application, and give the agent those plus your bill and pay stubs. Build the guard first, in a folder you keep for paperwork. Read every line of the filled form against your own documents before you sign it, and know that whatever the agent reads goes to the model provider.

Why an agent, not a chat window

A hook is a rule the tool runs before every action, not advice the model can forget. The agent writes one guard that both Claude Code and OMP enforce, then a fresh session does the paperwork under it. The same session without the guard is recorded next to it, so you can see what the guard stopped.