Daemon skill

Manage the public daemon profile — a digital representation of what you're working on.

by danielmiessler·MIT license·★ 19,269 Stars on the repo·GitHub ↗

Use now

Files of Daemon

danielmiessler/main1 file shown
SKILL.md
Show the full text207 lines

Customization

Before executing, check for user customizations at: ~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Daemon/

If this directory exists, load and apply any SecurityOverrides.md or PREFERENCES.md found there. These override default security classification. If the directory does not exist, proceed with skill defaults.

Voice Notification

curl -s -X POST http://localhost:31337/notify \
  -H "Content-Type: application/json" \
  -d '{"message": "Running the WORKFLOWNAME workflow in the Daemon skill to ACTION"}' \
  > /dev/null 2>&1 &

Daemon Skill

What It Does

Manages your public daemon profile — a living page of what you're working on, thinking about, reading, and building. It pulls data from your LifeOS system, runs it through a deterministic security filter so only publicly safe content survives, and deploys a static site. Workflows cover update, read, preview, and deploy.

The Problem

You want a public presence that stays current without hand-editing a profile page every week, and without ever leaking private data. Your real context lives in LifeOS — goals, projects, ideas, identity — mixed with things that must never go public: contacts, finances, health, names, paths, credentials. Manually copying the safe parts is slow and one slip publishes something you can't take back. This skill aggregates the safe sources, blocks the sensitive ones at the code level, and gives you a preview-then-approve gate before anything ships.

How It Works

The DaemonAggregator reads LifeOS sources and merges them into daemon-data.json; a deterministic SecurityFilter (pattern matching, not an LLM) strips names, paths, credentials, and internal refs; the deploy step builds a fully static site. Sensitive files are never opened by the aggregator at all.

Workflow Routing

Workflow Trigger File
UpdateDaemon "update daemon", "refresh daemon" Workflows/UpdateDaemon.md
ReadDaemon "read daemon", "check daemon", "daemon status" Workflows/ReadDaemon.md
PreviewDaemon "preview daemon", "daemon diff" Workflows/PreviewDaemon.md
DeployDaemon "deploy daemon", "push daemon", "ship daemon" Workflows/DeployDaemon.md

Architecture

Two-repo pattern: public framework + private content.

LifeOS SOURCES (private, read-only)
  TELOS/ (missions, goals, books, movies, wisdom)
  KNOWLEDGE/Ideas/ (title + thesis only)
  PROJECTS.md (public projects only)
  MEMORY/WORK/ (abstracted to topic themes)
  PRINCIPAL_IDENTITY.md (public bio data)
    │
    ├──[DaemonAggregator.ts]──→ Reads sources, merges with existing data
    │
    ├──[SecurityFilter.ts]──→ Deterministic code-level allowlist filter
    │                          Strips names, paths, credentials, internal refs
    │                          NOT an LLM filter — enforced by pattern matching
    │
    └──→ daemon-data.json → ~/Projects/daemon-dm/ (PRIVATE repo)
              │
              ├──[Tools/DeployGate.ts]──→ Deterministic pre-deploy gate (blocks on
              │                            expired/ungated ephemera, street-address/ZIP/
              │                            coordinate/home-area strings, unapproved
              │                            real-time phrasing, credentials, private feed URLs)
              │
              └──[deploy.sh]──→ Copies JSON into framework → VitePress build → Cloudflare WORKER
                                    │
                              ~/Projects/daemon/ (PUBLIC repo — forkable framework)
                                    │
                              src/worker.ts (generic):
                                • /daemon-data.json — served through the edge with expired
                                  ephemera STRIPPED at request time (status/now/offerings/
                                  requesting items with past `expires`; non-default location
                                  falls back to location_default)
                                • /feed.json — live-activity items aggregated every 30 min
                                  (cron + lazy refresh) from PUBLIC sources only, configured
                                  in daemon-data.json `feeds` (rss | beehiiv | github | x);
                                  cached in KV FEED_KV
                                • secrets (CF worker secrets, never in code): X_BEARER_TOKEN,
                                  BEEHIIV_API_KEY

    STRUCTURALLY EXCLUDED (never read):
          CONTACTS.md, FINANCES/, HEALTH/, TRAUMAS.md,
          KNOWLEDGE/People/, KNOWLEDGE/Companies/,

Skill Structure

skills/Daemon/
├── SKILL.md              (this file)
├── Tools/
│   ├── DaemonAggregator.ts   (reads LifeOS sources → daemon-data.json)
│   └── SecurityFilter.ts     (deterministic content sanitizer)
├── Workflows/
│   ├── UpdateDaemon.md       (aggregate → preview → approve → deploy)
│   ├── ReadDaemon.md         (read current daemon-data.json)
│   ├── PreviewDaemon.md      (show diff without deploying)
│   └── DeployDaemon.md       (bash deploy.sh from daemon-dm)
└── Docs/
    └── SecurityClassification.md  (public/private data categories)

Important Paths

Purpose Path
Private data repo ~/Projects/daemon-dm/
daemon-data.json ~/Projects/daemon-dm/daemon-data.json
Deploy script ~/Projects/daemon-dm/deploy.sh
Public framework repo ~/Projects/daemon/
Security classification ${LIFEOS_SKILL_DIR}/Docs/SecurityClassification.md
Security overrides ${LIFEOS_USER_DIR}/CUSTOMIZATIONS/SKILLS/Daemon/SecurityOverrides.md

Live Endpoints

Endpoint Purpose
daemon.example.com Public website (Cloudflare Pages, fully static)

Security Philosophy

  1. Private by default: All data is private until explicitly classified as public
  2. Code-level enforcement: SecurityFilter.ts is deterministic pattern matching, NOT LLM judgment
  3. Structural exclusion: Sensitive files (CONTACTS, FINANCES, HEALTH) are never opened by the aggregator
  4. Defense in depth: Aggregator filter + SecurityFilter + pre-commit hook + manual approval
  5. Fail closed: If uncertain, exclude the content

Data Sources

The DaemonAggregator reads from these LifeOS sources. Every source is read only if present (existsSync-guarded) — installs using the unified single-file TELOS.md layout won't have the per-file TELOS sources below, and the aggregator skips them cleanly (--sources shows per-source OK/MISSING status):

Source What's Extracted Section
TELOS/MISSION.md M1, M2 (public missions) [MISSION]
TELOS/GOALS.md Public project goals [TELOS]
TELOS/BOOKS.md Book titles [FAVORITE_BOOKS]
TELOS/MOVIES.md Movie titles [FAVORITE_MOVIES]
TELOS/WISDOM.md Top 5 quotes [WISDOM]
KNOWLEDGE/Ideas/_index.md 10 recent Ideas (title + thesis) [RECENT_IDEAS]
PROJECTS.md Public repos and sites Projects integration
MEMORY/WORK/ Topic themes (last 14 days) [CURRENTLY_WORKING_ON]
PRINCIPAL_IDENTITY.md Public bio, role, focus [ABOUT]
Existing daemon.md Preserved sections (predictions, routine, podcasts, preferences) Various

For Community Forks

This skill is designed to be generic:

  1. Fork the public Daemon repo
  2. Create your own private data repo with daemon-data.json
  3. Configure with your own blocked names/paths
  4. The aggregator reads from standard LifeOS directory structure
  5. Use deploy.sh to build and deploy to your own Cloudflare Pages

Examples

Example 1: Full update cycle

User: "update daemon"
→ Aggregates LifeOS data sources
→ Applies security filter (deterministic)
→ Shows preview diff to user
→ User approves
→ Writes daemon-data.json to daemon-dm → deploys static site

Example 2: Check what's current

User: "check daemon"
→ Reads daemon-data.json from daemon-dm
→ Shows section-by-section status

Example 3: Preview before committing

User: "preview daemon"
→ Runs aggregator in preview mode
→ Shows diff against current daemon-data.json
→ No writes, no deploys

Gotchas

  • Two repos: Public framework (~/Projects/daemon/) and private content (~/Projects/daemon-dm/). The framework is forkable. The content is yours.
  • deploy.sh runs DeployGate FIRST, then copies data into the framework at build time, then cleans up. A gate failure blocks the deploy — fix the data, never bypass the gate. Personal data never gets committed to the public repo.
  • SecurityFilter is code, not prompts. If you need to add new blocked patterns, edit SecurityFilter.ts, not the workflow markdown.
  • Ephemera needs expires. status, now (via now_meta), time-bound offerings/requesting items, and any non-default location all carry ISO expires fields. Three enforcement layers: DeployGate (blocks), the worker (strips at serve time), the dashboard (hides client-side). Refreshing a stale status = edit daemon-data.json with a new expires and run deploy.sh.
  • Location doctrine: coarse by default, real-time by exception. City/region granularity only; street/ZIP/coordinate/home-area strings are gate-blocked. "Tonight/I'm at" phrasing requires an explicit realtime_approved: true on that item — reserved for events where the principal WANTS to be findable. No automatic GPS/calendar pipeline; location changes only on explicit command.
  • The live feed is public-exhaust only. The worker polls blog RSS, Beehiiv (official API), YouTube RSS, GitHub public events, and the owner's own X posts — already-published content, zero privacy risk by construction. Never add a LifeOS-internal source to feeds.
  • Beehiiv blocks RSS scrapers (403). The newsletter source uses the official Beehiiv API (type: "beehiiv" + BEEHIIV_API_KEY worker secret), not the /feed URL.
  • Serving is edge-dynamic, page shell is static. /daemon-data.json and /feed.json are computed per-request by the worker (run_worker_first); the rest is static assets. Data changes still require deploy.sh; feed content refreshes itself.
  • The upstream framework repo publishes a GENERATED template (merge-back doctrine). Its main branch is a clean generic template published from a scrubbed staging copy, never a working tree pushed directly: the template excludes analytics, licensed fonts, favicons, and all personal content, and its identity is data-driven (owner_name/owner_handle/fork_url in daemon-data.json). The publish workflow is maintainer-side and does not ship; on an installed system your daemon content lives in your own private repo and only the framework is forkable.

Execution Log

After completing any workflow, append a single JSONL entry:

echo '{"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","skill":"Daemon","workflow":"WORKFLOW_USED","input":"8_WORD_SUMMARY","status":"ok|error","duration_s":SECONDS}' >> ~/.claude/LIFEOS/MEMORY/SKILLS/execution.jsonl
1---
2name: Daemon
3version: 1.0.25
4description: "Manage the public daemon profile — a digital representation of what you're working on. DaemonAggregator reads LifeOS sources (TELOS, KNOWLEDGE, PROJECTS, MEMORY/WORK, identity) → daemon-data.json. SecurityFilter strips names/paths/credentials via deterministic patterns (NOT LLM). Workflows: UpdateDaemon, ReadDaemon, PreviewDaemon, DeployDaemon. USE WHEN daemon, update daemon, daemon profile, deploy daemon, preview daemon, read daemon, public profile, digital presence. NOT FOR LifeOS system management."
5---
6 
7## Customization
8 
9**Before executing, check for user customizations at:**
10`~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Daemon/`
11 
12If this directory exists, load and apply any SecurityOverrides.md or PREFERENCES.md found there. These override default security classification. If the directory does not exist, proceed with skill defaults.
13 
14## Voice Notification
15 
16```bash
17curl -s -X POST http://localhost:31337/notify \
18 -H "Content-Type: application/json" \
19 -d '{"message": "Running the WORKFLOWNAME workflow in the Daemon skill to ACTION"}' \
20 > /dev/null 2>&1 &
21```
22 
23# Daemon Skill
24 
25## What It Does
26 
27Manages your public daemon profile — a living page of what you're working on, thinking about, reading, and building. It pulls data from your LifeOS system, runs it through a deterministic security filter so only publicly safe content survives, and deploys a static site. Workflows cover update, read, preview, and deploy.
28 
29## The Problem
30 
31You want a public presence that stays current without hand-editing a profile page every week, and without ever leaking private data. Your real context lives in LifeOS — goals, projects, ideas, identity — mixed with things that must never go public: contacts, finances, health, names, paths, credentials. Manually copying the safe parts is slow and one slip publishes something you can't take back. This skill aggregates the safe sources, blocks the sensitive ones at the code level, and gives you a preview-then-approve gate before anything ships.
32 
33## How It Works
34 
35The DaemonAggregator reads LifeOS sources and merges them into `daemon-data.json`; a deterministic SecurityFilter (pattern matching, not an LLM) strips names, paths, credentials, and internal refs; the deploy step builds a fully static site. Sensitive files are never opened by the aggregator at all.
36 
37## Workflow Routing
38 
39| Workflow | Trigger | File |
40|----------|---------|------|
41| **UpdateDaemon** | "update daemon", "refresh daemon" | `Workflows/UpdateDaemon.md` |
42| **ReadDaemon** | "read daemon", "check daemon", "daemon status" | `Workflows/ReadDaemon.md` |
43| **PreviewDaemon** | "preview daemon", "daemon diff" | `Workflows/PreviewDaemon.md` |
44| **DeployDaemon** | "deploy daemon", "push daemon", "ship daemon" | `Workflows/DeployDaemon.md` |
45 
46## Architecture
47 
48Two-repo pattern: public framework + private content.
49 
50```
51LifeOS SOURCES (private, read-only)
52 TELOS/ (missions, goals, books, movies, wisdom)
53 KNOWLEDGE/Ideas/ (title + thesis only)
54 PROJECTS.md (public projects only)
55 MEMORY/WORK/ (abstracted to topic themes)
56 PRINCIPAL_IDENTITY.md (public bio data)
57 │
58 ├──[DaemonAggregator.ts]──→ Reads sources, merges with existing data
59 │
60 ├──[SecurityFilter.ts]──→ Deterministic code-level allowlist filter
61 │ Strips names, paths, credentials, internal refs
62 │ NOT an LLM filter — enforced by pattern matching
63 │
64 └──→ daemon-data.json → ~/Projects/daemon-dm/ (PRIVATE repo)
65 │
66 ├──[Tools/DeployGate.ts]──→ Deterministic pre-deploy gate (blocks on
67 │ expired/ungated ephemera, street-address/ZIP/
68 │ coordinate/home-area strings, unapproved
69 │ real-time phrasing, credentials, private feed URLs)
70 │
71 └──[deploy.sh]──→ Copies JSON into framework → VitePress build → Cloudflare WORKER
72 │
73 ~/Projects/daemon/ (PUBLIC repo — forkable framework)
74 │
75 src/worker.ts (generic):
76 • /daemon-data.json — served through the edge with expired
77 ephemera STRIPPED at request time (status/now/offerings/
78 requesting items with past `expires`; non-default location
79 falls back to location_default)
80 • /feed.json — live-activity items aggregated every 30 min
81 (cron + lazy refresh) from PUBLIC sources only, configured
82 in daemon-data.json `feeds` (rss | beehiiv | github | x);
83 cached in KV FEED_KV
84 • secrets (CF worker secrets, never in code): X_BEARER_TOKEN,
85 BEEHIIV_API_KEY
86 
87 STRUCTURALLY EXCLUDED (never read):
88 CONTACTS.md, FINANCES/, HEALTH/, TRAUMAS.md,
89 KNOWLEDGE/People/, KNOWLEDGE/Companies/,
90```
91 
92## Skill Structure
93 
94```
95skills/Daemon/
96├── SKILL.md (this file)
97├── Tools/
98│ ├── DaemonAggregator.ts (reads LifeOS sources → daemon-data.json)
99│ └── SecurityFilter.ts (deterministic content sanitizer)
100├── Workflows/
101│ ├── UpdateDaemon.md (aggregate → preview → approve → deploy)
102│ ├── ReadDaemon.md (read current daemon-data.json)
103│ ├── PreviewDaemon.md (show diff without deploying)
104│ └── DeployDaemon.md (bash deploy.sh from daemon-dm)
105└── Docs/
106 └── SecurityClassification.md (public/private data categories)
107```
108 
109## Important Paths
110 
111| Purpose | Path |
112|---------|------|
113| **Private data repo** | `~/Projects/daemon-dm/` |
114| **daemon-data.json** | `~/Projects/daemon-dm/daemon-data.json` |
115| **Deploy script** | `~/Projects/daemon-dm/deploy.sh` |
116| **Public framework repo** | `~/Projects/daemon/` |
117| **Security classification** | `${LIFEOS_SKILL_DIR}/Docs/SecurityClassification.md` |
118| **Security overrides** | `${LIFEOS_USER_DIR}/CUSTOMIZATIONS/SKILLS/Daemon/SecurityOverrides.md` |
119 
120## Live Endpoints
121 
122| Endpoint | Purpose |
123|----------|---------|
124| `daemon.example.com` | Public website (Cloudflare Pages, fully static) |
125 
126## Security Philosophy
127 
1281. **Private by default:** All data is private until explicitly classified as public
1292. **Code-level enforcement:** SecurityFilter.ts is deterministic pattern matching, NOT LLM judgment
1303. **Structural exclusion:** Sensitive files (CONTACTS, FINANCES, HEALTH) are never opened by the aggregator
1314. **Defense in depth:** Aggregator filter + SecurityFilter + pre-commit hook + manual approval
1325. **Fail closed:** If uncertain, exclude the content
133 
134## Data Sources
135 
136The DaemonAggregator reads from these LifeOS sources. Every source is read only if present (`existsSync`-guarded) — installs using the unified single-file `TELOS.md` layout won't have the per-file TELOS sources below, and the aggregator skips them cleanly (`--sources` shows per-source OK/MISSING status):
137 
138| Source | What's Extracted | Section |
139|--------|-----------------|---------|
140| TELOS/MISSION.md | M1, M2 (public missions) | [MISSION] |
141| TELOS/GOALS.md | Public project goals | [TELOS] |
142| TELOS/BOOKS.md | Book titles | [FAVORITE_BOOKS] |
143| TELOS/MOVIES.md | Movie titles | [FAVORITE_MOVIES] |
144| TELOS/WISDOM.md | Top 5 quotes | [WISDOM] |
145| KNOWLEDGE/Ideas/_index.md | 10 recent Ideas (title + thesis) | [RECENT_IDEAS] |
146| PROJECTS.md | Public repos and sites | Projects integration |
147| MEMORY/WORK/ | Topic themes (last 14 days) | [CURRENTLY_WORKING_ON] |
148| PRINCIPAL_IDENTITY.md | Public bio, role, focus | [ABOUT] |
149| Existing daemon.md | Preserved sections (predictions, routine, podcasts, preferences) | Various |
150 
151## For Community Forks
152 
153This skill is designed to be generic:
154 
1551. Fork the public Daemon repo
1562. Create your own private data repo with `daemon-data.json`
1573. Configure with your own blocked names/paths
1584. The aggregator reads from standard LifeOS directory structure
1595. Use `deploy.sh` to build and deploy to your own Cloudflare Pages
160 
161## Examples
162 
163**Example 1: Full update cycle**
164```
165User: "update daemon"
166→ Aggregates LifeOS data sources
167→ Applies security filter (deterministic)
168→ Shows preview diff to user
169→ User approves
170→ Writes daemon-data.json to daemon-dm → deploys static site
171```
172 
173**Example 2: Check what's current**
174```
175User: "check daemon"
176→ Reads daemon-data.json from daemon-dm
177→ Shows section-by-section status
178```
179 
180**Example 3: Preview before committing**
181```
182User: "preview daemon"
183→ Runs aggregator in preview mode
184→ Shows diff against current daemon-data.json
185→ No writes, no deploys
186```
187 
188## Gotchas
189 
190- **Two repos:** Public framework (`~/Projects/daemon/`) and private content (`~/Projects/daemon-dm/`). The framework is forkable. The content is yours.
191- **deploy.sh runs DeployGate FIRST, then copies data into the framework at build time, then cleans up.** A gate failure blocks the deploy — fix the data, never bypass the gate. Personal data never gets committed to the public repo.
192- **SecurityFilter is code, not prompts.** If you need to add new blocked patterns, edit SecurityFilter.ts, not the workflow markdown.
193- **Ephemera needs `expires`.** status, `now` (via now_meta), time-bound offerings/requesting items, and any non-default location all carry ISO `expires` fields. Three enforcement layers: DeployGate (blocks), the worker (strips at serve time), the dashboard (hides client-side). Refreshing a stale status = edit daemon-data.json with a new `expires` and run deploy.sh.
194- **Location doctrine: coarse by default, real-time by exception.** City/region granularity only; street/ZIP/coordinate/home-area strings are gate-blocked. "Tonight/I'm at" phrasing requires an explicit `realtime_approved: true` on that item — reserved for events where the principal WANTS to be findable. No automatic GPS/calendar pipeline; location changes only on explicit command.
195- **The live feed is public-exhaust only.** The worker polls blog RSS, Beehiiv (official API), YouTube RSS, GitHub public events, and the owner's own X posts — already-published content, zero privacy risk by construction. Never add a LifeOS-internal source to `feeds`.
196- **Beehiiv blocks RSS scrapers (403).** The newsletter source uses the official Beehiiv API (`type: "beehiiv"` + BEEHIIV_API_KEY worker secret), not the /feed URL.
197- **Serving is edge-dynamic, page shell is static.** /daemon-data.json and /feed.json are computed per-request by the worker (`run_worker_first`); the rest is static assets. Data changes still require `deploy.sh`; feed content refreshes itself.
198- **The upstream framework repo publishes a GENERATED template (merge-back doctrine).** Its main branch is a clean generic template published from a scrubbed staging copy, never a working tree pushed directly: the template excludes analytics, licensed fonts, favicons, and all personal content, and its identity is data-driven (owner_name/owner_handle/fork_url in daemon-data.json). The publish workflow is maintainer-side and does not ship; on an installed system your daemon content lives in your own private repo and only the framework is forkable.
199 
200## Execution Log
201 
202After completing any workflow, append a single JSONL entry:
203 
204```bash
205echo '{"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","skill":"Daemon","workflow":"WORKFLOW_USED","input":"8_WORD_SUMMARY","status":"ok|error","duration_s":SECONDS}' >> ~/.claude/LIFEOS/MEMORY/SKILLS/execution.jsonl
206```
207 

Discussion