From session-orchestrator
Creates idempotent daily note in Obsidian Meta-Vault (03-daily/YYYY-MM-DD.md) with vaultFrontmatterSchema-compliant YAML frontmatter. Re-run opens existing note. For work day starts, scratch notes, inbox bootstrapping.
npx claudepluginhub kanevry/session-orchestrator --plugin session-orchestratorThis skill uses the workspace's default tool permissions.
IMPLEMENTED 2026-04-13.
Guides strict Test-Driven Development (TDD): write failing tests first for features, bugfixes, refactors before any production code. Enforces red-green-refactor cycle.
Guides systematic root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
Guides A/B test setup with mandatory gates for hypothesis validation, metrics definition, sample size calculation, and execution readiness checks.
IMPLEMENTED 2026-04-13.
Bootstraps today's daily note in the Meta-Vault so the user can start capturing
thoughts, scratch work, and "done today" items without yak-shaving YAML
frontmatter each morning. The daily note is the anchor of the PKM workflow: it
is where the inbox flow starts, where daily momentum is tracked, and where
evening reflections land. Every daily note carries the same frontmatter shape
(validated by vaultFrontmatterSchema), which makes Dataview queries and the
vault-sync validator trivial.
03-daily/) OR
with VAULT_DIR resolved to the vault path (see Resolution Order below).03-daily/ must already exist — the skill fails fast if it does not.bash + sed + date (always available on macOS/Linux).vault-integration.vault-dir in Session Config (highest precedence)VAULT_DIR environment variable$PWD (fallback when neither is set)Claude must read Session Config and export VAULT_DIR before calling
generate.sh. The canonical pattern (mirrors session-end and evolve):
CONFIG=$(cat .orchestrator/session-config.yaml | yq -o json)
VM_DIR=$(echo "$CONFIG" | jq -r '."vault-integration"."vault-dir" // empty')
: "${VM_DIR:=$VAULT_DIR}"
VAULT_DIR="$VM_DIR" bash /path/to/skills/daily/generate.sh
generate.sh itself reads only VAULT_DIR (pure bash, no Config parser).
VAULT_DIR. Check vault-integration.vault-dir in Session
Config first; fall back to the VAULT_DIR env var; then $PWD. The
config field takes precedence — see Prerequisites for the canonical
resolution snippet. generate.sh then validates: template exists (exit 2
if not), vault dir exists (exit 3 if not), 03-daily/ exists (exit 4 if
not).date +%Y-%m-%d — ISO 8601 date-only, respecting
the system timezone (the user is in Vienna, so Europe/Vienna via system TZ).$VAULT_DIR/03-daily/YYYY-MM-DD.md.Daily note already exists: <path> and exit 0. Never overwrite.templates/daily.md.tpl (next to this SKILL.md)
and substitute {{date}}, {{id}}, {{created}}, {{updated}},
{{title}}, {{weekday}} via sed. The template is literal markdown; the
only shell interpolation happens in the sed substitutions.sed … > "$TARGET.tmp" && mv "$TARGET.tmp" "$TARGET" to avoid leaving a half-written file on disk if sed fails.generate.sh). Callers
should run the vault-sync validator over the vault in hard mode to confirm
schema compliance:
VAULT_DIR="$VAULT_DIR" bash ../vault-sync/validator.sh --mode hard
The BATS test suite runs this check on every run — see
tests/daily.bats. If validation ever fails, the template has drifted from
the canonical Zod schema; fix the template, do not downgrade the gate.Created daily note: <path> on stdout, exit 0.The deterministic path is implemented in generate.sh (pure bash). An
LLM-driven fallback is unnecessary: daily-note creation is a 100%
mechanical transform and a shell script is faster, cheaper, and more
reliable than an LLM round-trip. Recommended invocation:
# Resolve vault dir from Session Config first, env var as fallback:
CONFIG=$(cat .orchestrator/session-config.yaml | yq -o json)
VM_DIR=$(echo "$CONFIG" | jq -r '."vault-integration"."vault-dir" // empty')
: "${VM_DIR:=$VAULT_DIR}"
VAULT_DIR="$VM_DIR" bash ~/Projects/session-orchestrator/skills/daily/generate.sh
Or, if VAULT_DIR is already set in the environment and Session Config has
no vault-integration.vault-dir override:
VAULT_DIR=~/Projects/vault bash ~/Projects/session-orchestrator/skills/daily/generate.sh
Or, if the user's cwd is already the vault:
cd ~/Projects/vault && bash ~/Projects/session-orchestrator/skills/daily/generate.sh
| Placeholder | Example | Format |
|---|---|---|
{{date}} | 2026-04-13 | ISO 8601 date (YYYY-MM-DD), also used inside the id |
{{created}} | 2026-04-13 | ISO 8601 date (YYYY-MM-DD) — matches isoDateRegex |
{{updated}} | 2026-04-13 | ISO 8601 date (YYYY-MM-DD) — matches isoDateRegex |
{{title}} | Daily 2026-04-13 | Human-readable heading, Daily YYYY-MM-DD |
{{weekday}} | Montag | Full German weekday name (lookup table keyed on date +%u) |
Note: {{id}} is not a separate placeholder — the template inlines
id: daily-{{date}} so there is only one date substitution. This keeps
template rendering to a single sed pass and prevents drift between id
and filename.
The German weekday is computed via a hardcoded lookup (1=Montag,
2=Dienstag, ..., 7=Sonntag) rather than LC_TIME=de_DE.UTF-8 date +%A
because not every macOS install has the de_DE.UTF-8 locale compiled.
The template must stay in sync with vaultFrontmatterSchema. The canonical
schema lives at:
~/Projects/projects-baseline/packages/zod-schemas/src/vault-frontmatter.ts
Required fields produced by the template: id, type, created, updated.
Optional-but-useful fields: title, tags, status. The type is hardcoded
to daily (one of the valid values in vaultNoteTypeSchema). The id is
daily-YYYY-MM-DD which is kebab-case and 16 chars — passes
slugRegex.min(2).max(128).
The BATS suite runs the vault-sync validator end-to-end (bats tests/daily.bats
→ test 8), so any drift between the template and the schema breaks the build
of this skill, not of the vault that consumes it.
Running generate.sh twice on the same day is a no-op when the existing
file is valid:
$VAULT_DIR/03-daily/YYYY-MM-DD.md.---\n (valid YAML frontmatter opener), prints
Daily note already exists: <path>, and exits 0.If the existing file is 0 bytes or lacks the ---\n opener (e.g. a previous
run crashed between the $TARGET.tmp write and the mv), the corrupt file
is removed and the note is re-created cleanly.
The file is never re-rendered when intact. This matters because the user
edits the daily note throughout the day (ticking checkboxes, filling in the
Scratch section, etc.) and re-invoking /daily from anywhere — a later
session, a different tool, a keybind — must not destroy that work.
Verified by tests/daily.bats test 5: hash-compares the file before and after
a second generate.sh invocation.
/daily is routine;
losing the day's scratch notes is catastrophic. The idempotency check is
load-bearing.VAULT_DIR is the contract. Hardcoding
~/Projects/vault breaks tests, breaks any future multi-vault setup, and
couples this skill to one user's machine.LC_TIME for the weekday. The locale is not guaranteed to
exist. Use the hardcoded lookup table.sed-unsafe characters to the template. The placeholders use
| as the sed delimiter; if you add a | to any substituted value, sed
will break. Keep substitutions plain.| Code | Meaning |
|---|---|
| 0 | Success (created) or idempotent skip (already exists and valid) |
| 1 | Unexpected runtime failure (set -e caught an unhandled error) |
| 2 | Infra error: template file not found at $SCRIPT_DIR/templates/daily.md.tpl |
| 3 | Config error: VAULT_DIR does not exist as a directory |
| 4 | Vault structure error: $VAULT_DIR/03-daily/ directory is missing |
SKILL.md — this file.generate.sh — the POSIX bash implementation of the algorithm above.templates/daily.md.tpl — the daily-note template with {{placeholder}}
markers.tests/daily.bats — 8 BATS test cases covering creation, substitution,
idempotency, missing-dir errors, and end-to-end schema validation via
vault-sync.From the skill directory:
bats tests/daily.bats
Expected: 8/8 passing. Test 8 runs the vault-sync validator over a fixture
vault that contains only the freshly-generated daily note, proving end-to-end
schema compliance.