@life-os/cli
v0.1.4
Published
Headless, config-aware CLI for reading and querying a LifeOS vault — built for AI agents
Maintainers
Readme
@lifeos/cli — lifeos
Headless, config-aware command-line interface over a LifeOS vault, built for AI agents (Claude Code, etc.). Lets an agent initialize, migrate, read, query, and edit a LifeOS knowledge base without opening Obsidian or Aino.
Why it exists
Unlike the official Obsidian CLI (a remote control for a running app), lifeos
works directly on the vault folder. It reuses the same engine
(@lifeos/vault-lifeos-service → @lifeos/query-core + @lifeos/markdown-indexer)
that powers Aino and the daemons, so query results match exactly what you see in
the plugin.
Config-aware: it reads your real settings from the same sources the rest of LifeOS uses, in this order:
.obsidian/plugins/periodic-para/data.json.obsidian/plugins/lifeos-pro/data.json.lifeos/settings.json(Aino's vault-portable settings)
So PARA folder names, periodic-note formats, habit/section headers and templates
all come from your configuration, not hardcoded defaults. Run lifeos config
to see exactly what was picked up.
Vault selection (first match wins)
vault=<path>option$LIFEOS_VAULTenv var- Walk up from the current directory for
.obsidian/,.lifeos/, or.agents/skills/lifeos/ - The folder Aino last opened (
userData/bootstrap.json→lastOpenedFolder)
The cwd walk comes before the Aino fallback by design: when an agent works inside a vault, the cwd is the most reliable signal of which vault the user means. Aino's last-opened folder is only used when running outside any vault.
onboard intentionally uses an empty current directory instead of that Aino
fallback, so a new local folder is safe to initialize. Pass vault=<path> when
the onboarding target is a different directory.
Commands
# Read / query
lifeos config # effective settings + where they came from
lifeos tasks [todo|done|all] # list tasks (filters: tag=, keyword=, due=today|week|overdue, limit=)
lifeos search query=<text> # find notes (type=file default | tag | content); add `case` for content
lifeos read file=<name>|path=<p> # print a note
# Onboarding any local Markdown folder (.obsidian is optional)
lifeos onboard inspect --json
lifeos onboard templates locale=en
lifeos onboard plan profile=para density=minimal locale=en
lifeos onboard apply profile=para density=minimal locale=en
lifeos onboard classify-input profile=para locale=en limit=30 --json
lifeos onboard classify-plan file=.lifeos/classification-plans/batch.json --json
lifeos onboard classify-apply file=.lifeos/classification-plans/batch.json --json
# Periodic notes — daily|weekly|monthly|quarterly|yearly (path from periodicNotesPath + format)
lifeos daily [date=YYYY-MM-DD] # show the note path + whether it exists
lifeos weekly:read [date=] # read the note
lifeos monthly:append content=<t> # append to the note (creates it if missing)
# Write
lifeos append path=<p> content=<t> # append text to an existing note
lifeos create path=<p> [content=] # create a note (add `overwrite` to replace)
lifeos task done|todo ref=<f>:<n> # toggle a task by its file:line reference
lifeos helpEvery command accepts --json for machine-readable output.
Onboarding supports PARA, IPO, and GTD directly; use the separate opc skill
for OPC. Inventory recognizes .md, .markdown, and common image, video,
audio, PDF, document, and presentation attachments without extracting binary
contents. Template and classification writes are previewed first. Confirmed
classification batches reject paths outside the workspace, target collisions,
and moves that could break links.
Examples
lifeos config vault="~/Documents/My Vault"
lifeos tasks todo due=week limit=20
lifeos tasks done tag=个人品牌 --json
lifeos search query=项目 type=file
lifeos read file="WOT-分享会.README"
lifeos append path="1. 项目/x.md" content="- new bullet"
lifeos create path="3. 资源/RAG 调研" content="# RAG 调研"
lifeos task done ref="0. 周期笔记/2025/Daily/05/2025-05-30.md:14"Writes take an explicit path= / ref= (no name guessing), so the agent should
search / tasks first to get the exact target, then write.
Syntax
Options use key=value (or --key=value); flags are bare --flag. This mirrors
the Obsidian CLI convention so agent prompting transfers.
Agent skill
The LifeOS agent skill is bundled into the CLI from @lifeos/skill-assets.
Install or update it into the current vault after upgrading @life-os/cli:
npx -y @life-os/cli skill installThis writes SKILL.md and its references/ files into
.agents/skills/lifeos/ from the exact CLI package version you are running.
Build & test
pnpm -C apps/lifeos-cli build
pnpm -C apps/lifeos-cli testScope
This CLI is the knowledge-base data layer of LifeOS: onboarding, migration, read/query/write of note content, tasks, PARA and tags. It deliberately does not wrap the plugin's UI views or background network sync (Google Calendar / CalDAV / two-way task sync) — those stay in the plugin and Aino.
Periodic-note resolution
All five period types reuse @lifeos/shared's buildPeriodicNotePath — the exact
formatter the plugin and Aino use (ISO weeks, matching the plugin's getPeriodicFile)
— over the resolved periodicNotesPath + per-type format, so they land on the same
files. Weekday/month tokens (dddd/MMMM) use native Intl with a locale
(locale=, default system). Every form prints the resolved path and Exists
status; if a vault's config diverges from how existing notes were named (e.g.
Aino's .lifeos/settings.json has a _dddd suffix the on-disk files lack), that
shows up as Exists: no rather than a silent mis-write.
Known limitations / next
tasks/searchcontent scan re-reads files per call (no persistent cache) — fine for one-shot CLI use, but not for tight loops.search type=contentis a plain substring match (no regex yet).
Publishing
The workspace package is @lifeos/cli; it is published to public npm as
@life-os/cli (its own org, since the @lifeos/* source scope is
workspace-internal — see docs/decisions/scope-strategy.md).
pnpm -C apps/lifeos-cli build:release bundles the CLI and all internal
@lifeos/* deps into a single self-contained dist/lifeos.mjs (via esbuild) and
stages a clean, dependency-free CLI-only package under
apps/lifeos-cli/release/. Then:
pnpm -C apps/lifeos-cli build:release:dry-run # bundle + npm pack --dry-run
cd apps/lifeos-cli/release && npm publish # publishes @life-os/cliEnd users then npm i -g @life-os/cli; the installed command is lifeos.
