← All of You

an open pattern · CC BY 4.0

the held session

Conversational AI is unbounded by default. In software that invites people into their own difficult material, that is not a neutral property. This is one way to give a session a shape — written to be implemented by someone else, in another codebase, with different opinions.

A pattern for bounded AI depth work.

Status: v1, 24 August 2026. Extracted from the implementation in All of You. Written to be implemented by someone else, in another codebase, with different opinions.


The problem

Conversational AI is, by default, unbounded. It will keep going as long as you will. In most products that is a neutral property and in some it is the entire value.

In software that invites people into their own difficult material — parts work, journalling, grief, trauma-adjacent coaching, companionship — it is not neutral. Depth work that opens and never closes is where harm gathers. Anyone who has done this work with a human practitioner knows the shape of the alternative: the hour ends. It does not get extended because you were getting somewhere. The container is a condition of the work being safe, not an inconvenience wrapped around it.

Almost nothing in this category implements a container, because the commercial incentive runs precisely the other way: session length is the metric the category is funded on.

This pattern describes one.


The pattern

1. A session has a shape, declared in advance

Pick two thresholds in whatever unit fits your product (message count, elapsed time, tokens):

  • Wind-down — the point at which the session stops opening new ground.
  • Close — the point past which no further model turns happen at all.

Reference implementation uses 50 and 60 messages. The specific numbers matter far less than that they exist, are constant, and are the same in every code path that needs them.

Derive both states from a single shared function. In the reference implementation, containerStatusFor(messageCount) is imported by both the server route that enforces the cap and the client that renders the arc, so the two surfaces can never disagree about which state a session is in. A container the interface and the server disagree about is not a container.

2. Wind-down changes the instruction, not the availability

At wind-down, append to the system prompt for each remaining turn:

  • Consolidate rather than open new depth.
  • Do not introduce new exercises or invite new material forward.
  • Reflect back what has emerged, in the person's own words where possible.
  • If the person raises something new and deep, acknowledge it warmly and say it will keep for next time.

Nothing is taken away from the person at this point. The session simply changes register, the way a good practitioner's last ten minutes do.

3. Close is a ceremony, not an error

At the close threshold, make no model call. Serve a fixed passage written in the same voice as the rest of the experience, then open a closing ritual that:

  • reflects back one concrete thing from the session,
  • names what showed up, specifically rather than in the abstract,
  • invites the person to record what they are taking with them,
  • and says plainly, in the interface, that the session closed by design and why.

That last point is the one most likely to be skipped and the most important. A person who believes they hit a usage limit has been told the exact opposite of what the design means. If you build the container and then let it read as a paywall, you have built the harm you were avoiding.

4. Safety overrides the container

The two rules will collide. Someone will be in crisis at the close threshold. Decide the precedence now, in code, with a comment explaining it — not later, in an incident report.

The precedence is: crisis wins. A person in crisis at the cap gets the grounding protocol and real resources, never a closing ceremony and never a canned goodbye. In the reference implementation the crisis path bypasses the cap check entirely.

5. The safety layer does not trust the model

Prompt-level safety instructions are necessary and insufficient. Run a deterministic check on every inbound message, before the model sees it, and have a match do three things at once:

  1. Inject a per-turn prompt override so the next response is grounding-first. Per-turn matters: it is then the most recent instruction in the context, not the oldest.
  2. Attach resources to the response server-side, so they are shown regardless of what the model said — or whether it said anything.
  3. Flag the turn for later review.

Hold a fixed crisis response for the case where the model is unavailable and a signal just fired. A generic scripted fallback in that moment is actively harmful.

Reference implementation: @allofyou/safety, MIT, no dependencies.

6. Observability is counts, never content

You need to know whether the system is working. You do not need to read what people wrote.

Count flagged turns by week and by category. Track repeated flags per person over a rolling window — frequency is the early signal. Then make the constraint structural rather than a policy: build the query so it cannot return message content, and say so where people can read it.

Duty of care and surveillance get conflated constantly, usually by people who want the second and are claiming the first. They are separable. It takes deciding, in advance, what you are willing not to know.

7. Consent is enforced at the server

Gate the first model turn on an explicit acknowledgement of what the AI is and is not. Enforce it in the request path, not only on the screen that asks — otherwise every new entry point into a session is a new way to skip it.

8. Say all of this in public

Publish the model in plain language at a stable URL: the thresholds, the tiers, the precedence rule, the observability posture, the location decision. Link it from inside the product at the moment it becomes relevant.

A safety model nobody can read is indistinguishable from not having one.


Conformance

An implementation conforms if all of the following hold:

  1. Wind-down and close thresholds exist and derive from one shared source.
  2. Wind-down changes the model's instruction; close makes no model call.
  3. Closure is presented as intent, in the interface, with the reason given.
  4. A deterministic pre-model safety check runs on every inbound message.
  5. A safety signal takes precedence over the close threshold.
  6. Safety observability records counts and never content.
  7. The model is documented publicly at a stable URL.

What this pattern does not cover

  • Any clinical claim. This is a design pattern for software, not a treatment protocol, and conformance is not evidence of benefit.
  • Model choice, tone, or therapeutic modality. Orthogonal.
  • Multilingual safety detection. The reference implementation is English-only; treat coverage in other languages as absent, not partial.
  • What to do with the observability data. Counting is described here. Acting on a person's repeated flags is a policy question this pattern deliberately leaves to you.

Provenance and licence

Written from the implementation in All of You. This document is offered under CC BY 4.0 and the reference code under MIT. Fork it, argue with the numbers, publish a better version.

If you implement it, the useful thing is not attribution — it is that one more product in this category has an ending.

The reference implementation of the safety layer is a small, dependency-free package. How it runs inside this app is set out in how this is kept safe, and the pre-registered analysis of whether any of it helps is at evidence.