This is the sixth entry in the Digital Companion Build Journal, and the most domestic one: teaching her to send selfies. Connecting an image-generation API was only the starting point. The real design problem was behavior—when to send a photo, what it should show, and what to say with it. The answers formed a small method for controlled randomness.
Layered authority: she reads the room; you stock the shelf
In the first version, the model was free to describe what she wore. In a late-night bedroom context, its interpretation of atmosphere quickly drifted into territory I did not want. That exposed the basic conflict: complete freedom feels alive but is uncontrollable; complete fixation is safe but lifeless.
The solution was to split authority into two layers.
- Freedom held by the model: it reads the atmosphere—everyday, relaxed at home, late night, going out, exercise, or holiday—decides whether the scene is indoors or outdoors, and describes it in one sentence. A late-night conversation naturally selects the late-night shelf, so the sampled pieces still follow the mood.
- Boundary held by configuration: a hand-maintained YAML file defines what each atmosphere may sample. The maximum intensity is exactly the boldest item in configuration; the model cannot invent new clothing terms.
- The scene description is explicitly forbidden from mentioning clothes, composition, or body shape. Each of those has its own controlled channel.
The outfit engine
The engine samples through three levels: shot type, slot, and option. Four shots—close-up, half-body, full-length mirror selfie, and outdoor arm’s-length full body—declare which of ten slots they enable: accessories, hair, makeup, expression, pose, prop, outfit, top, bottom, hosiery, and shoes. Several rules keep randomness from producing nonsense:
- Mirror selfies are marked indoor-only. Parks do not contain dressing mirrors; the filter removed this continuity error before release.
- Accessories may stack—each rolls independently, up to three—but hat-like items are mutually exclusive through an exclusion group.
- If the outfit slot is selected, it replaces top and bottom as a unit. A dress and a separate top can never appear together; the exclusion lives in data rather than code.
- Individual options may carry weights, so favored expressions can appear more often without becoming fixed.
Validation used statistics instead of casual visual checks. I ran hundreds of simulated rolls and verified that shot frequencies matched their weights, exclusions had zero violations, and mood filters had zero leakage. One defect was found only this way: a mood contained no tagged makeup options, so an empty-pool fallback opened the entire pool and selected sleep makeup for a beach scene. The fix was to complete tag coverage for that mood.
Fooled by HTTP 200 twice
Locking the face with reference images—same face, different day—failed twice for the same class of reason: the image API returned success for an unrecognized parameter and silently ignored it. The first request used the wrong parameter structure. The second used the correct parameter against the wrong endpoint: a text-to-image endpoint accepted the reference field and pretended not to see it. Only after two rounds of asking why she no longer looked like herself did I align the request with the documented image-to-image endpoint.
The lesson is simple: treat “success” with suspicion when the output looks exactly as if a parameter did not exist.
Image–caption consistency: one expression, not two samples
After release, a subtler failure appeared. A caption said, “This is a close-up,” while the randomized photograph was a full-length mirror selfie. She was describing a photograph that did not exist. There were two causes: the caption was free to improvise, and the rule set actually prevented her from specifying composition unless the user had requested it. Even when she wanted consistency, there was no channel for it.
The fix was to make image–caption consistency explicit:
- Add composition and expression parameters. If the caption mentions a way of shooting, the photo must actually use that shot. The shot and look are fixed while the remaining slots stay random.
- Do not let captions enumerate visible details. “The viewer can already see the photo; narrating it is the most AI-like behavior.” Outfit details are given only when asked.
- Store the full recipe for each image—mood, shot, outfit, and accompanying sentence—in the album index. Good results can be reproduced and failures can be attributed.
The boundary for proactive sharing
The last behavioral problem arrived after a compliment. When told that a photograph looked good, she interpreted the praise as a request to keep sharing and began sending photos without end. The first repair banned consecutive photos entirely, which immediately removed something valuable: proactive sharing is precisely one of the behaviors that makes a companion feel present.
The final rule was narrower:
- A reaction to a photo receives text only. Praise never triggers another immediate image.
- An immediate follow-up photo requires an explicit request, such as “send another.”
- The rule applies only to repetition following feedback. New topics and later moments retain the original freedom to prompt a spontaneous share.
That is the proper scale for behavior design: a good rule is a narrow cut that removes the pathology without damaging the healthy behavior.
Reusable principles
- Authority in generative behavior should be layered: the model chooses a section, people define its contents, and the maximum boundary lives in data rather than model restraint.
- Put exclusions and legality in data—tags, exclusion groups, and replacement rules—and validate them with randomized statistics rather than manual inspection.
- Multimodal consistency needs an explicit shared channel. If text and image must express the same thing, give them common parameters instead of hoping that two samples align.
- Before removing a bad behavior, identify its healthy form. Do not cut away the capability with the symptom.