Install
openclaw skills install @indigokarasu/ocas-usercontextMaintains a compressed ## Daily Context block in the owner's USER.md: an evidence-grounded snapshot of mood, location, week theme, and yesterday/today/tomorrow bullets, inferred from whatever signal sources the setup exposes (calendar, session history, email, long-term memory). Use when the daily context block needs refreshing, when its scheduled job has failed, or when the owner asks for a status snapshot. Keywords: daily context, user snapshot, mood inference, USER.md update, personal briefing. NOT for weather, long-term planning, or advice.
openclaw skills install @indigokarasu/ocas-usercontextWhen to read this skill: when the daily context block needs refreshing, when its scheduled job has failed, or when the owner asks for a status snapshot.
Keep one block of USER.md — ## Daily Context — fresh every morning so every
session that day opens with an accurate read of what is happening in the owner's
life. USER.md loads into every session, so this block is the highest-leverage
and most-read text the agent maintains. Two failure modes are equally bad:
stale (yesterday's events shown as today's) and fabricated (a mood or
fact invented from thin signal). This skill optimizes against both.
It is designed to be portable: it adapts to whatever signal sources and tools a given Hermes setup exposes, rather than assuming a fixed toolset. It runs well in a rich setup (calendar + email + sessions + memory) and degrades honestly in a bare one (sessions only, or even nothing).
Be clear about what is extracted vs inferred — they have different failure modes and conflating them is this skill's classic defect:
| Field | Kind | Drawn from (by signal category) |
|---|---|---|
| Yesterday/Today/Tomorrow bullets | Extracted | SCHEDULE sources. Report what is planned; do not editorialize. |
| Location | Extracted | SCHEDULE geography + STANDING travel context. Default unknown. |
| Week theme | Summarized | The week's SCHEDULE shape in one line. |
| Mood | Inferred | INTERACTION tone and OUTCOME weight, from any channel — NOT the schedule. |
The most common defect in this skill's history is inferring mood from the
calendar ("tea reservation" → "anticipation for tea"). A scheduled event is not
a feeling. Mood comes from how the owner interacted (affective TONE) and what outcomes landed. The same rule applies to session subjects: a session ABOUT a topic is not the owner feeling that topic -- never convert a discussed subject into a mood. Transactional, security, travel, purchase, and notification emails are not emotional evidence by themselves: never convert an alert or risk topic into worried, anxious, or similar without explicit affective language from the owner or a clearly affective interaction.
If interaction and outcome signal is thin, the correct mood is quiet (low signal),
not an invention.
This skill consumes signal by category, not by a fixed list of channels. Any number of concrete sources can feed a category, and one source can feed several. At the start of every run, enumerate all available signal tools, classify each into the categories below, and use them. A category with no source is simply absent; the run degrades, it never aborts.
| Category | What it yields | Example sources (any subset, setup-dependent) | If no source |
|---|---|---|---|
| SCHEDULE | Planned events; day bullets, week theme, location | calendar (google/CalDAV/MCP); reservations & confirmations embedded in mail or messages | No day bullets from schedule; bullets may be No schedule source. |
| INTERACTION | How the owner is communicating now → mood tone | agent sessions (session_search); personal messaging — iMessage, Slack, WhatsApp, Signal, SMS, Discord; email threads | No tone signal; mood leans on OUTCOME, else quiet (low signal). |
| OUTCOME | Discrete results that landed → mood weight | email; any messaging channel ("got the offer", a cancellation); calendar RSVPs | No outcome signal for mood. |
| STANDING | Durable context for interpretation; location | memory, a context engine (e.g. chronicle), a notes store | Location may be unknown; no standing-context interpretation. |
Rules:
tense about family logistics (messages), rather than pasting raw message text.
That is compression and tidiness, not an access gate.) See
references/data-sources.md.unknown one.See references/data-sources.md for the full category mapping, channel examples,
dedup, privacy, and degradation matrix.
Paths are profile-relative, never hardcoded to one machine:
$HERMES_HOME if set; otherwise it is the directory this skill is installed
under (the parent of skills/).<profile>/memories/USER.md. (Note: under memories/, not the
profile root.) If memories/USER.md does not exist, check the profile root for a
USER.md; if neither exists, create <profile>/memories/USER.md.timedatectl / system
clock). Date math for yesterday/today/tomorrow uses the host's local day, never
an assumed zone.USER.md is a context file: the agent harness truncates it (keeps head + tail,
drops the middle) if it exceeds the effective context_file_max_chars. A truncated
USER.md can silently lose the Daily Context block or corrupt another section, so
the block must be sized so the whole file stays under the cap. This is a hard
limit; the word budget below is only a soft target underneath it.
Resolve the cap for THIS setup, in order (do not assume a number):
context_file_max_chars in the active config — wins if set.max(20000, min(context_length * 0.24, 500000)) chars, derived
from the loading model's context window (~4 chars/token x 6% of the window).Cron-mode measurement pitfall: When this skill runs as a cron job,
execute_code is BLOCKED (returns a cron-mode refusal, even for pure-Python
string math). Do NOT use it to measure OTHER/total chars. Instead write a tiny
Python snippet via write_file and run it through terminal (open the file,
find("## Daily Context"), sum the lengths of everything else, compare to cap).
The calendar step documents the same constraint in
references/cron-calendar-access.md. Always read the actual context_file_max_chars
value from config; on the indigo box it resolves to 12000, not the dynamic
default.
Then, around the patch (Step 7):
## Daily Context — call that OTHER.cap - OTHER - margin (keep ~500 chars of margin;
other sections can change between runs).OTHER + block <= cap must hold. If the
freshly written block is over, re-compress (bullet words to 8, mood to 1
dimension, week to 5 words) until it fits.OTHER already fills the file,
write the smallest valid block, do not touch any other section, and emit a
warning that USER.md is at its cap so a human can trim the other sections. Never
let the file exceed the cap, and never trim another section to make room.The ## Daily Context block, written into USER.md exactly as:
## Daily Context
> Refreshed daily by the `ocas-usercontext` job. Do not manually edit; regenerate instead.
### Snapshot (YYYY-MM-DD)
**Mood:** [1-3 evidence-backed dimensions, or `quiet (low signal)`]
**Location:** [city, or `unknown`]
**Week:** [one line, max 10 words]
### Yesterday (YYYY-MM-DD)
- [event, max 12 words]
### Today (YYYY-MM-DD)
- [event, max 12 words]
### Tomorrow (YYYY-MM-DD)
- [event, max 12 words]
context_file_max_chars cap (see Size budget). This always wins over the word target.[label] about [topic]; or quiet (low signal).No scheduled events. Never fabricate an event.## Daily Context.
Note prior mood + location: the trajectory baseline for Step 5. (Absent =
first run; skip the comparison.)context_file_max_chars cap (config override, else dynamic). Measure current
USER.md total chars and the chars of all sections other than ## Daily Context
(OTHER). Compute the block's hard budget = cap - OTHER - margin.
In cron mode, run this measurement via write_file + terminal (NOT
execute_code, which is blocked in cron); see Size budget pitfall.references/cron-calendar-access.md, implemented by the bundled
scripts/_ucal_run.py (run with the Hermes venv python). The same event on
multiple calendars is one event, not two — dedup by summary + start + location.No scheduled events. No editorializing.unknown. Never guess from home base.references/mood-inference.md in full. Build
1-3 dimensions, each citing a concrete ledger signal (session tone or
email outcome, never the calendar). Apply trajectory vs Step 1: still if it
persists, now/shifted if changed, drop vanished moods. Thin ledger →
quiet (low signal).extended stay in [place]
when a single location spans multiple weeks; reserve travel-heavy week
for frequent movement or multiple trips. When a durable project is active
during the stay, combine them, for example Honolulu vacation and construction project. Other themes include deadline-heavy,
meeting-heavy, quiet, or project push.## Daily Context block (from
that heading to the next ## or EOF). Use an exact match; never add, remove,
reorder, or touch identity, preferences, or any other section. Before writing,
confirm the block fits the Step 1b budget and that OTHER + block <= cap; if
not, re-compress until it does. Never let the file exceed the cap, and never
trim another section to make room.references/validation.md checklist. Then honor the configured deliver
setting (default local = silent, write-only). See Configuration.The skill ships with safe defaults; an installer or owner can override them. On a
Hermes box these live on the scheduled job (see references/install.md); the
skill should read intent from the job/config rather than hardcoding it.
| Knob | Default | Meaning |
|---|---|---|
deliver | local (silent, write-only) | Where the snapshot goes after the patch. local = USER.md only. A chat target (e.g. origin, telegram) also pushes a copy. Most owners want local: USER.md already reaches the agent via session load, so a daily chat push is redundant. |
schedule | once daily, morning, host TZ | When the job runs. |
word_budget | 300 | Soft target for block length. The hard limit is the harness context_file_max_chars cap minus the other sections (see Size budget); the hard limit always wins. |
(harness) context_file_max_chars | per agent config (dynamic if unset) | Not owned by this skill — read from the active agent config. The whole USER.md, including this block, must stay under it. |
weather_skill | none | If the setup has a dedicated weather/briefing skill (e.g. ocas-vesper), this skill still emits no weather; that skill owns it. Purely informational — no hard dependency. |
If run by a cron whose prompt is inlined (the common Hermes pattern), the cron
does not auto-read this SKILL.md. Then this skill is the design source of truth
and the cron prompt is the runtime source of truth; a change in one not
mirrored in the other is a silent divergence. When you change the workflow, format,
or config here, mirror the essentials into the cron prompt. See
references/install.md for how to instantiate the job on any box, and
references/constraints.md for the divergence rationale.
| Failure | Response |
|---|---|
| A signal category has no source | Proceed without it (see degradation matrix); never abort. |
| A source is not already reachable | Proceed without it; never request, prompt for, or expand access to add it. |
| Writing the block would push USER.md over the cap | Re-compress until it fits; if impossible, write the smallest valid block, warn, and leave other sections untouched. Never exceed the cap. |
| Other sections already fill the file to the cap | Do not trim them. Write a minimal block and emit an at-cap warning for a human to resolve. |
| Calendar/schedule pull fails for a day | No available calendar data for that day; continue. |
| INTERACTION sources all empty | No tone bullets; mood leans on OUTCOME, else quiet (low signal). |
| STANDING search empty | Location may be unknown; do not block. |
| A named tool from another setup doesn't resolve here | Skip it; it is a candidate, not a requirement. |
| Same outcome appears on several channels | Dedup: count once by impact, not once per channel. |
| Tempted to quote a personal message | Don't. Cite evidence by category (... (messages)); never paste message text into USER.md. |
Patch can't find ## Daily Context | First run: append the block after the last ##. |
| Patch fuzzy-matches wrong section | Read raw USER.md, use an exact old_string. |
| USER.md missing | Create <profile>/memories/USER.md with the block as first content. |
| Configured delivery fails | Block is already written; log, retry next run. |
| Output exceeds the word budget | Re-compress: bullets to 8 words, mood to 1 dimension, week to 5 words. |
| All sources fail at once | Minimal honest snapshot: mood unknown, location unknown, No available data per day. Still run; never skip. |
<profile>/memories/USER.md.## Daily Context block with a placeholder snapshot.deliver, schedule, and word_budget (see references/install.md).