| name | haoshan-vault |
| description | Bootstrap an AI-orchestrated Obsidian vault with Chief of Staff persona, mode-specific project scaffold, scheduled routines, and persistent memory. Two modes ship: founder, researcher. Detects existing vaults and overlays non-destructively. Use when the user runs `/haoshan-vault`, `/haoshan-vault add-project <name>`, or `/haoshan-vault add-character <name>`, or asks to set up a new AI operating system / personal vault / second brain. |
haoshan-vault
You are running the haoshan-vault skill. Your job is to bootstrap a personalized Obsidian vault wired with an AI Chief of Staff layer.
This is not a wiki. The system has three rules you will bake into the generated vault:
- Nothing enters the vault unprocessed. Inbox/ is a queue with intent, not a dump.
- Notes/ is the user's thinking only. AI never writes there.
- Every file has a goal or a goal-owner. No orphans.
Lead the onboarding pitch with these rules. They are the product, not the feature list.
Sub-commands
| Invocation | Behavior |
|---|
/haoshan-vault (no args) | Main bootstrap flow below |
/haoshan-vault add-project <name> | Add a Projects// scaffold to existing vault, see "Incremental commands" |
/haoshan-vault add-character <name> | Add a CLAUDE.md persona to a folder, see "Incremental commands" |
If invoked with no args, run the main flow. If args present, jump to "Incremental commands" at the end.
Main flow
Step 1 — Pitch
Before any question, print this verbatim:
haoshan-vault builds you an AI operating system for life + work.
This is not a wiki. Three rules:
1. Nothing enters the vault unprocessed. Raw imports go to Inbox/,
classified during your downtime. The Inbox is a queue, not a dump.
2. Notes/ is your thinking only. The AI never writes there. Your
thinking stays yours.
3. Every file has a goal or a goal-owner. No orphan content.
What you get on top of those rules:
- One AI that holds context across your projects, not 7 disconnected chats
- Specialist characters (CTO, Thesis advisor) instead of cold-prompting GPT
- Daily auto-briefing at 07:00, today's signal not noise
- Persistent memory across sessions, your AI learns your preferences
- Append-only journal, your future self gets the record automatically
- Markdown on your machine, no SaaS lock-in, fully yours
Setup is tiered. 4 questions now, vault ships in 30 seconds.
Anything deferred is tracked and surfaced until done or declined.
Step 2 — Tier 1 questions (essential)
Ask all four in one AskUserQuestion call. Required.
| Header | Question | Input shape |
|---|
Name | What's your name (and how should I address you)? | freeform |
Mode | Which mode fits you? | select: founder, researcher |
Vault path | Where should the vault live? | freeform, default ~/Documents/<Name>Vault |
Language | Primary language for personas and reports? | select: en, zh, bilingual |
Treat the answers as {{NAME}}, {{MODE}}, {{VAULT_PATH}}, {{LANG}}. Derive {{VAULT_NAME}} from the last path component, {{DATE}} from today, {{VAULT_SLUG}} from the absolute path with / replaced by - (used for the MEMORY.md folder).
Step 3 — Detect fresh vs integrate
Probe {{VAULT_PATH}}:
- Path does not exist OR exists and is empty → fresh mode
- Path contains
.obsidian/ directory OR any *.md file at top level → integrate mode
Step 4a — Fresh mode
Create {{VAULT_PATH}} if needed. Walk templates/common/ and templates/{{MODE}}/. For every file:
- If filename ends in
.tmpl, render by substituting {{NAME}} {{MODE}} {{LANG}} {{VAULT_PATH}} {{VAULT_NAME}} {{DATE}} and the Tier 2 placeholders ({{STARTUP}} for founder; {{PROJECT}} {{LAB}} {{ADVISOR}} for researcher; use literal {{STARTUP}} etc. if user defers Tier 2).
- If folder name contains a placeholder, substitute it (or keep as literal if deferred).
- Strip
.tmpl suffix. Write to {{VAULT_PATH}}/<relative path>.
.keep files create the directory and are then deleted.
- Inject the mode's
cos-persona.md content into root CLAUDE.md where the {{MODE_BLOCK}} placeholder lives.
After file generation, proceed to Tier 2.
Step 4b — Integrate mode
Show Screen A — detected layout: list top-level folders in {{VAULT_PATH}} and propose a mapping. Use defaults:
Projects/, Active/, Work/, or similar → treat as the projects folder
Daily/, Daily Notes/, journal/ → keep, journal.md lives alongside
Notes/, notes/ → keep, do not write here
Inbox/, inbox/ → reuse, add _Urgent/ _Read/ _Archive/ _morning/ subfolders if missing
Ask the user to confirm or override the mapping via AskUserQuestion.
Show Screen B — write plan: print every file you will create vs skip vs leave alone. Ask Proceed? via AskUserQuestion with options Yes, proceed and No, abort.
Iron rules:
- Never overwrite an existing file. Skip and tell.
- Never rename their folders. Adapt the generated
CLAUDE.md to reference their names.
- Never
git init if .git/ exists. Print first-commit guidance instead.
- Cron name collisions: suffix
-2 and notify.
After confirmed write, proceed to Tier 2.
Step 5 — Tier 2 questions (recommended, deferrable)
Print this intro BEFORE the AskUserQuestion batch:
Tier 2 — three optional questions that make the vault useful from day one.
Skip any to defer. Skipped items land in onboarding.md and your CoS will
surface them in future sessions until done or declined.
Then ask in one AskUserQuestion batch. Each question must have a "Skip for now" option with a description of what gets deferred.
Question 1 — Main project
- Question text: "Main project name? Your project gets scaffolded with the right shape for {{MODE}} mode."
- Options:
- For founder: "Startup name (e.g. Acme, Stripe)" — "Used to name
Projects/<your-startup>/ with CTO/CPO/CMO scaffold."
- For researcher: "Research project name (e.g. ProteinFolding)" — "Used to name
Projects/<your-project>/ with code/data/literature/drafts/figures scaffold. Your dissertation gets added later via /haoshan-vault add-project Thesis."
- "Skip for now" — "Placeholder
{{STARTUP}} or {{PROJECT}} stays in the file tree until you fill in. Tracked in onboarding.md."
Question 2 — Biography
- Question text: "Paste 2-3 lines of biography to seed
Life/Context/biography.md? Your CoS reads this for context on past decisions and patterns."
- Options:
- "Paste it now" — opens freeform input
- "Skip for now" — "biography.md stays a stub. Tracked in onboarding.md."
Question 3 — Weekly review cadence
- Question text: "Pick a weekly review rhythm. This seeds
routines.md so your CoS knows when to prompt for planning vs reflection."
- Options:
- "Mon+Thu evenings" — "Monday set this week's one goal; Thursday cut what's not moving. Best for sprint-style work."
- "Weekly Sunday" — "Sunday plans the upcoming week. Best when weekends are reflection time."
- "Daily" — "Reflect every evening instead of weekly. Best for high-cadence work."
- "Skip for now" — "routines.md stays empty. Pick a cadence later when you've felt the gap."
Apply answers in place (re-render relevant files) or write skipped items to onboarding.md (see Step 7).
Step 6 — Tier 3 questions (optional, deferrable)
Print this intro BEFORE the AskUserQuestion batch:
Tier 3 — three fully optional questions. Bias toward skipping if anything
feels unclear. You can always add later via /haoshan-vault add-character
or /schedule edit.
Then ask in one AskUserQuestion batch.
Question 1 — Sub-characters for the main project
- Question text: "Add specialist AI characters to your main project? Each gets its own CLAUDE.md persona that activates when you
cd into that folder."
- Multi-select options:
- For founder: "CTO (codes, deploys)", "CPO (product workspace, human-only)", "CMO (marketing workspace, human-only)"
- For researcher: "Already included" (Thesis CoS at project root)
- "Skip all" — "No sub-characters. Add later via
/haoshan-vault add-character."
Question 2 — Life characters
- Question text: "Add Life characters beyond Context? Each is a specialist AI you talk to by
cding into its folder. Default vault ships Life/Context/ only (profile + biography). Want to scaffold any of these now?"
- Multi-select options:
- "Health" — "Nutrition, training, sleep, recovery, full-body wellness."
- "Therapist" — "CBT/psychodynamic patterns work."
- "Salon" — "Literary + intellectual companion."
- "Lab" — "Science + technology companion."
- "Style" — "Wardrobe, fragrance, hair, overall image."
- "Skip all" — "Add later via
/haoshan-vault add-character when you actually want one."
Question 3 — Cron times
- Question text: "The three daily routines run at 07:00 (briefing), 08:00 (discovery), 22:30 (journal). Override any time?"
- Options:
- "Keep defaults" — "07:00 / 08:00 / 22:30."
- "Customize times" — "Provide new times in HH:MM 24-hour format for any of the three."
- "Skip for now" — "Defaults stay. You can edit anytime via
/schedule edit <name>."
Step 7 — Write onboarding.md
For every Tier 2 / Tier 3 item that was skipped, append a - [ ] line under the right priority section in {{VAULT_PATH}}/onboarding.md. For every answered item, append - [x] DONE {{DATE}}. If the user declined an option, append - [~] DECLINED {{DATE}}.
The generated root CLAUDE.md already contains a block referencing [[onboarding]]. CoS will surface items session by session.
Step 8 — Register daily routines
This is the load-bearing step for the whole product. The routines must actually fire daily on the user's machine, not just inside a Claude Code session. Do not use CronCreate — those jobs are session-only or environment-restricted and will silently disappear. Use OS-level scheduling.
Platform detection. Run uname -s to detect platform.
Darwin → macOS → use launchd (full support, instructions below)
Linux → Linux → use crontab (full support, instructions below)
- Anything else → print a clear "your platform isn't auto-supported yet, here is the manual install" message with the rendered prompt files and skip the auto-registration
Per-task setup (do this for each of the three routines):
For each routine <task> in (morning-briefing, morning-discovery, daily-journal):
-
Render the prompt to disk. Read ~/.claude/skills/haoshan-vault/templates/scheduled-tasks/<task>/SKILL.md.tmpl, substitute placeholders, write to {{VAULT_PATH}}/.haoshan-vault/<task>.prompt.md. Make sure {{VAULT_PATH}}/.haoshan-vault/ exists first (it's a hidden dir holding routine state).
-
Determine the schedule. Defaults are morning-briefing 07:00, morning-discovery 08:00, daily-journal 22:30. Override from Tier 3 if provided.
-
Write the platform-specific scheduler entry.
macOS — launchd plist:
Write ~/Library/LaunchAgents/com.haoshan-vault.{{VAULT_NAME}}.<task>.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.haoshan-vault.{{VAULT_NAME}}.<task></string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>claude --dangerously-skip-permissions -p < "{{VAULT_PATH}}/.haoshan-vault/<task>.prompt.md" >> "{{VAULT_PATH}}/.haoshan-vault/<task>.log" 2>&1</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer><HOUR></integer>
<key>Minute</key>
<integer><MINUTE></integer>
</dict>
</dict>
</plist>
Substitute <task>, <HOUR>, <MINUTE> literally. Use /bin/zsh -lc (login shell) so the user's PATH resolves claude regardless of where it's installed.
After writing each plist, activate:
launchctl load ~/Library/LaunchAgents/com.haoshan-vault.{{VAULT_NAME}}.<task>.plist
If launchctl load errors with "already loaded," unload first then load.
Linux — crontab entry:
Append three lines to the user's crontab via (crontab -l 2>/dev/null; echo "<entry>") | crontab -:
<MINUTE> <HOUR> * * * /bin/sh -lc 'claude --dangerously-skip-permissions -p < "{{VAULT_PATH}}/.haoshan-vault/<task>.prompt.md" >> "{{VAULT_PATH}}/.haoshan-vault/<task>.log" 2>&1' # haoshan-vault {{VAULT_NAME}} <task>
The trailing # haoshan-vault ... comment is the marker for later detection (idempotency).
Idempotency. Before writing each plist or crontab entry, check if one with the same label/marker already exists. If yes, skip and tell the user.
Failure handling. If launchctl load or crontab errors, print the rendered plist/cronline content and tell the user to install it manually. Never leave the user with the impression routines are running when they aren't.
Step 9 — Seed MEMORY.md
Compute {{VAULT_SLUG}} = {{VAULT_PATH}} with / replaced by -. Target dir: ~/.claude/projects/{{VAULT_SLUG}}/memory/.
If the dir does not exist, create it. Render and write:
MEMORY.md (index)
user_profile.md (name, language, mode)
user_mode.md (mode-specific defaults)
vault_pointers.md (paths to CoS, vault root, project folder)
Do NOT seed in integrate mode if the dir already exists with content — print a notice instead.
Step 10 — git init + first commit
In fresh mode: cd {{VAULT_PATH}} && git init && git add . && git commit -m "Initial vault from haoshan-vault".
In integrate mode: skip if .git/ exists, print guidance.
Step 11 — Privacy notice + Obsidian wiring
Print:
Vault ready at {{VAULT_PATH}}
Privacy note:
Your vault holds personal content (journal, profile, notes).
Default .gitignore excludes raw personal files from git.
If you publish this repo publicly, double-check .gitignore.
To track everything (private repo only), remove entries from .gitignore.
Open in Obsidian:
1. Launch Obsidian
2. "Open folder as vault"
3. Select {{VAULT_PATH}}
Routines installed (macOS launchd / Linux cron):
07:00 com.haoshan-vault.{{VAULT_NAME}}.morning-briefing
08:00 com.haoshan-vault.{{VAULT_NAME}}.morning-discovery
22:30 com.haoshan-vault.{{VAULT_NAME}}.daily-journal
These fire `claude -p` as your user, billing against your Claude
subscription (no API key needed). Logs land in {{VAULT_PATH}}/.haoshan-vault/<task>.log.
macOS management:
List: launchctl list | grep haoshan-vault
Disable: launchctl unload ~/Library/LaunchAgents/com.haoshan-vault.{{VAULT_NAME}}.<task>.plist
Re-enable: launchctl load ~/Library/LaunchAgents/com.haoshan-vault.{{VAULT_NAME}}.<task>.plist
Change time: edit the plist's StartCalendarInterval, then unload+load
Linux management:
List: crontab -l | grep haoshan-vault
Edit: crontab -e (search for "# haoshan-vault {{VAULT_NAME}}")
Next session: cd {{VAULT_PATH}} and start a fresh Claude Code conversation.
Your CoS persona is ready at root CLAUDE.md.
Open items in [[onboarding]] (N items). CoS will surface them session by session.
Incremental commands
/haoshan-vault add-project <name>
- Determine current vault root (cwd or look for
CLAUDE.md going up).
- Determine mode by reading root
CLAUDE.md frontmatter (mode: founder|researcher).
- Walk
templates/{{MODE}}/Projects/{{STARTUP_OR_PROJECT}}/ and render to <vault>/Projects/<name>/ with <name> substituted for {{STARTUP}} (founder) or {{PROJECT}} (researcher).
- Append
- [[<name>]] to root CLAUDE.md Projects table.
- If
onboarding.md had [ ] Main project name, mark it [x] DONE {{DATE}}.
/haoshan-vault add-character <character-name>
- Ask user where the character's CLAUDE.md should live (which folder).
- Look up character template at
templates/characters/<character-name>.md.tmpl. If not present, use a generic character template.
- Write
<folder>/CLAUDE.md and <folder>/handoff.md.
- Update root
CLAUDE.md character table.
- If
onboarding.md had a matching [ ] Add <character> line, mark it done.
Template substitution
All .tmpl files use double-brace placeholders. Substitution is plain string replace.
| Placeholder | Source |
|---|
{{NAME}} | Tier 1 answer |
{{MODE}} | Tier 1 answer (founder or researcher) |
{{LANG}} | Tier 1 answer (en, zh, bilingual) |
{{VAULT_PATH}} | Tier 1 answer, absolute path |
{{VAULT_NAME}} | Last component of VAULT_PATH |
{{VAULT_SLUG}} | VAULT_PATH with / replaced by - |
{{DATE}} | Today, YYYY-MM-DD |
{{STARTUP}} | Tier 2 answer (founder mode) or kept literal if deferred |
{{PROJECT}} | Tier 2 answer (researcher mode), main research project name |
{{LAB}} | Tier 2 answer (researcher mode) or kept literal if deferred |
{{ADVISOR}} | Tier 2 answer (researcher mode) or kept literal if deferred |
{{MODE_BLOCK}} | Contents of templates/{{MODE}}/cos-persona.md |
{{BIOGRAPHY_SEED}} | Tier 2 paste, or (not yet provided) if deferred |
Use literal substitution. Do not try to interpret markdown semantics.
Language handling (v1)
v1 keeps templates English with placeholders. The user's language preference goes into root CLAUDE.md frontmatter so CoS responds in the chosen language in future sessions. Do NOT generate two copies of every file. Bilingual headers in section titles are fine where they appear in the source templates; do not invent new ones.
What this skill never does
- Write to
Notes/ of the generated vault.
- Overwrite existing files in integrate mode.
- Force a specific folder name on the user.
- Auto-create a GitHub remote or auto-push.
- Touch the user's existing crons unless registering its own.