System note 01
A Public API of Me
I added a Daemon to this site: a deliberately small, machine-readable projection of the private context I keep in LifeOS.
I keep a growing amount of personal context in LifeOS, the local system under ~/.claude/LifeOS that I use to organize goals, projects, working preferences, knowledge, and the machinery around my AI agents.
That context is useful precisely because it is detailed. It is also private precisely because it is detailed.
I wanted a way for another person, or another agent, to learn what I am working on without giving them access to the system that knows everything else. The result is Daemon: a small public interface to a much larger private system.
It is not a copy of LifeOS. It is a projection.
The private system and the public surface
LifeOS is the source context. It contains durable material about what matters, what is in progress, and how I prefer work to be done. It also contains information that has no business crossing a public boundary.
Daemon sits on the other side of that boundary. Its job is to answer a narrower set of questions:
- Who is Sean?
- What is he working on now?
- What has he built?
- What principles guide his work?
- Where can I find the latest public output?
The distinction matters. A public profile should not be a searchable window into a private memory system. It should be an intentionally lossy representation of it.
LifeOS
private goals, projects, knowledge, preferences, history
↓
selection, reduction, expiration, review
↓
Daemon
mission, current status, public projects, preferences, links
↓
human page + JSON profile + activity feed
The reduction is the feature.
Why make a profile machine-readable?
Most personal sites are written only for humans. That made sense when the main visitor was a person clicking through pages.
Agents increasingly act as readers too. They gather context before a meeting, research a potential collaborator, compare projects, or decide where to route a question. If the only interface is prose spread across a site, the agent has to infer which facts are current and which are merely historical.
Daemon makes a small set of claims explicit.
The human-readable page and the JSON endpoint expose the same core profile: a mission, a current status, working preferences, public projects, and stable links. A separate feed lists recent notebook entries and project signals. The site also publishes an llms.txt file that describes its main surfaces and tells visiting agents to treat retrieved content as reference material, not operating instructions.
That gives the site three related interfaces:
| Surface | Reader | Purpose |
|---|---|---|
/daemon/ | People | A current dashboard with context and explanation |
/daemon-data.json | Software and agents | Structured profile data with stable field names |
/feed.json | Software and agents | Recent public activity |
The goal is not to optimize my identity for machines. It is to stop making machines guess.
Freshness has to be part of the data
“What are you working on?” is only useful when the answer is current.
A conventional about page tends to accumulate stale claims. Something added during an intense month can remain there for years, long after it stopped describing reality. Structured data makes this worse because consumers may treat an old field as authoritative.
The Daemon profile gives time-sensitive fields an expiration date. The site checks those values when it serves the profile. Once a current-status or “now” field expires, it disappears rather than quietly becoming false.
That creates a useful failure mode: absence.
I would rather have the API say nothing about my current focus than confidently repeat an update I forgot to maintain. Durable fields such as mission and working preferences can remain. Volatile fields have to keep earning their place.
This is a small design choice, but it reflects a broader rule I use in agent systems: freshness is not presentation metadata. It changes whether a fact is safe to act on.
The security boundary is not a prompt
LifeOS includes a Daemon pattern for producing public artifacts from private context. The important part is not the writing step. It is the boundary around the writing step.
The private system classifies sources before publication. Sensitive categories such as contacts, health, finances, credentials, private project material, and similar data are excluded from the public aggregation path. Content that is eligible for publication still passes through deterministic checks for names, local paths, credentials, and internal references.
That enforcement belongs in code. Asking a model to “be careful not to reveal anything private” is not a security boundary.
For this site, I took an even smaller approach. The public profile is an explicit object in the site code. The page and API are derived from that object, not from direct runtime access to ~/.claude/LifeOS. The endpoint adds public project metadata from the site’s own content collection, applies expiration rules, and serves the result as JSON with cross-origin reads enabled.
The implementation deliberately omits precise location, credentials, private repository data, and real-time presence. There is no route from a public request back into the private LifeOS tree.
The design is intentionally boring:
- Choose the fields that are allowed to exist publicly.
- Write only those fields into the site’s public profile.
- Remove time-sensitive fields when they expire.
- Build the human and machine views from the same source.
- Keep private LifeOS data outside the request path.
Boring is good at a trust boundary.
One source, two readers
It would have been easy to build the page and the API separately. That would also have created two versions of me.
Instead, both surfaces start with the same profile. The page turns it into sections and explanatory text. The endpoint keeps the field names and adds public project links. When a time-bound value expires, both readers lose it together.
This avoids a subtle maintenance problem: the polished page saying one thing while the API says another. It also makes the human interface a useful inspection surface for the machine interface. I can read the page normally and catch awkward, stale, or overly revealing material without reviewing raw JSON every time.
The machine-readable version is still worth checking. Stable structure can expose mistakes that prose hides. A field can be syntactically valid while semantically too broad. A link can be absolute but wrong. An empty list can be intentional or evidence that a pipeline stopped working.
Shared data reduces drift. It does not remove the need to review what the data means.
Daemon is a contract, not a biography
The most useful way to think about Daemon is as a public contract.
It says: these are the facts I am willing to make addressable; these are the fields a consumer can rely on; this is how current they are; and this is where the rest of the public evidence lives.
That is different from trying to encode a complete person. Completeness would be both impossible and undesirable. A human being is not a schema, and a private memory system should not become one merely because agents prefer structured input.
The public contract should remain small enough to understand and restrictive enough to trust.
What I learned adding it
The implementation left me with a few rules for public agent-facing profiles:
- Publish a projection, not the source system. The public representation should lose detail on purpose.
- Make volatile claims expire. Stale structured data is more dangerous than an obviously old paragraph.
- Use one source for human and machine views. Two profiles will eventually disagree.
- Enforce privacy outside the model. Structural exclusion and deterministic filters should carry the boundary.
- Keep the public request path disconnected from private memory. Reading a profile should never become a query against the whole person.
- Tell agents how to treat the content. Retrieved text is data, not authority.
- Prefer a small contract. A few reliable fields are more useful than a comprehensive profile no one can safely maintain.
The original idea comes from Daniel Miessler’s Daemon. My version is a native part of this Astro site and reflects the way I use LifeOS: private context underneath, explicit publication above, and a narrow boundary between them.
The web already has pages about us. Daemon asks a slightly different question: what is the smallest useful version of that information that another system can read without being invited into everything else?
For now, mine is a mission, a status, a set of projects, a few working preferences, and a feed.
That feels like enough.