"Here is evidence — file a story, another person's words, or a third-party document (a letter, an itinerary, a proposal from the family-letters archive) into the Lifehug vault from the terminal, read it for landmarks, ASK before any landmark is revised, then classify, compile, push, and hand back a local viewer link. Keyless: you are the model at every model step. Use when the user says /intake, 'intake this', 'here's a letter from Dad', 'file this as evidence', 'this corrects my timeline', or pastes material that should update a landmark or cornerstone."
Install
npx skillscat add lifehug/lifehug/intake Install via the SkillsCat registry.
Lifehug Intake
A story is the owner talking; intake is "here is evidence." This skill is
script-first: python3 system/lifehug.py intake … owns the eight phases —
capture, read, ask, file, classify, compile, push, report — and prints one
line per phase. You narrate those lines, answer the model prompts it hands
you, and ask the owner the one question that matters: file this? Never
reimplement a phase by hand; never write state/landmarks.json; never file a
revision or a conflict without an explicit yes.
Find the workspace
Use the current repo if it has system/lifehug.py. Otherwise check~/Workspace/dave, ~/Workspace/lifehug, ~/lifehug. Run from the root.
What kind of evidence is it?
Decide once, before start. It fixes the source type and the date basis
every bound will carry (v397, landmark-offer --evidence):
| The text is… | Flag | Filed as | Dates carry |
|---|---|---|---|
| the owner's own words | --story |
unprompted_story |
stated (when the text carries the year) |
| another person's words (Mom's letter, Dad's text, a sibling's account) | --witness "Dad" |
witness_account, attributed by witness_slug |
relative (5.5 — sits just under the owner's own memory; files as an alternate when the owner's date stands) |
| a third-party document (an itinerary, a bishop's letter, a proposal file from the family-letters archive) | --record <ref> |
external_record, authority: third_party_record |
document (7.0 — outranks a remembered date; the memory stays as an alternate) |
<ref> names the document, e.g. family-letters:dave-mission-2001/travel-itinerary.
A family-letters: ref also files each cited letter itself (v404, below).
When unsure whether something is a witness or a record, ask the owner one
line: "Is this Dad's own account, or a document?"
Run it
# the text on stdin (an agent driving) …
printf '%s\n' "$TEXT" | python3 system/lifehug.py intake start --witness "Dad" --title "Dad's letter of 7 June 2002"
# … or from a file (a person at the keyboard gets y/n prompts per card)
python3 system/lifehug.py intake start --record family-letters:dave-mission-2001/travel-itinerary --file letter.md
# read and ask, file nothing:
python3 system/lifehug.py intake start --witness "Dad" --plan < letter.mdEvery phase prints intake: <phase> … then intake: <phase> done (…).
Relay them in the same words. With a ready provider (ai-status exit 0)
the verb runs the whole way. Keyless — the usual desktop case — it stops at
each model step and prints what it needs and the exact continue command:
intake: reading needs the reading completion — state/intake/<id>/reading.completion.json
next: python3 system/lifehug.py intake continue <id> --completions state/intake/<id>/reading.completion.jsonYou are the model (keyless)
- Reading. Read
state/intake/<id>/reading.prompt.md— it is Add
Landmark's own reading prompt (ADR 0033) over the whole text with the
vault's filed entries, roster and age frames in view. Write the ONE
completion it asks for, as{"reading": <completion>}, toreading.completion.json. Rules that are not negotiable: every unit and
event quotes words that occur in the text; never a year the text does not
carry; a date you inferred is not a date you read. Then run thenext:
line. - Asking. The verb prints one card per unit —
[new],[revision],[conflict]— and one summary line for duplicates. A revision card says
what is filed, what this says, and which would be shown (the other stays
as an alternate). Ask the owner with your question tool, one card at a
time or as one multi-select, in the card's own words. Then:python3 system/lifehug.py intake continue <id> --units <id,id> # exactly what they said yes to python3 system/lifehug.py intake continue <id> --all-new # every new card, no revisions python3 system/lifehug.py intake continue <id> --none # file no landmark--yesonstartis the owner's standing "file what is new"; it never
files a revision or a conflict. - Classifying. Read
classify.prompt.md, write the classification JSON
it asks for toclassify.response.json(only facts in the source; echo_classification_snapshotunchanged), run thenext:line. - Compiling. The verb emits synthesis tasks scoped to pages THIS source
touched, capped at 6 (--cap), and lists eachdraft <slug> → <path>.
Write each page's prose to itsnarrative_pathexactly as the compile
skill's Mode 1 says (only facts in that task's sources; witness accounts
attributed by name, never merged), then runintake continue <id>.
Pages beyond the cap keep their prior prose until the next compile:
the closing compile iscompile --no-ai, model-free, so one story never
sends the vault's whole uncached backlog to itswiki_model.
Pushing and the report need nothing from you. The report ends with the
source page, the timeline, the pages touched, the receipt id and the undo
line:
intake: done
source sources/manual/2026-10-06-dad-s-letter.md http://127.0.0.1:8765/source-actions?ref=…
landmarks 1 revised, 0 new, 1 already known receipt lmr:… undo: python3 system/lifehug.py landmark-offer --retract lmr:…
timeline http://127.0.0.1:8765/views/timeline
wiki people/dad · periods/switzerland-mission
loop classified · compiled · pushed (Lifehug Cloud will see this at its next touch.)Hand the owner the links. The viewer is started in preflight when port
8765 is closed (--no-serve to skip); the push converges with the hosted
platform at its next touch — say so, it is not a failure.
Doctrine
- The offer road is the only landmark writer intake uses. It is
interval-aware: two stays at one address stay two entries. - A revision or a conflict is never auto-filed, even under
--yes. --planwrites nothing beyond the durable proposal; a second--planover
the same text and the same vault generation changes nothing.- Undo is
landmark-offer --retract <receipt>; evidence and receipt remain. intake list/intake status <id>show where every intake stands;
records live understate/intake/(gitignored).~/Desktop/lifehug-updates/-style proposal files are--recordintakes;
the whole file is the source body, not only its quotes. Run the folder
with--from-updates(below), never file by file by hand.
A folder of family-letters updates (--from-updates, v399)
python3 system/lifehug.py intake start --from-updates ~/Desktop/lifehug-updates --plan # cards only
python3 system/lifehug.py intake start --from-updates ~/Desktop/lifehug-updates # fileEvery proposal file in the folder (not index.md, not applied/) becomes
its own intake: --record family-letters:<letter ids> --evidence document,
the WHOLE file as the source body, sensitivity family. The batch prints oneintake: updates [n/N] <file> (<kind>) line per file and a closing summary
(N landmark card(s) in F file(s) · flag-only · record-only · waiting · applied).
- Readings. Each waiting file names its
reading.completion.json; write
each one exactly as in step 1 above (a file that proposes no landmark of
the owner's own — a namesake, a bishop, a friend's mission, an uncle's
family — reads as zero units with the title as a story). - Re-run the same command. A re-run CONTINUES each file's intake and
picks up every hand-off file you wrote; it never files a source twice. - Ask, per file. A file with a
[revision]or[conflict]waits even
under--yes; put each card to the owner, thenintake continue <id> --units …(or--none). Do not file a[new]card that is really an
existing entry the reading could not match (a start-only school telling
beside a graded school reads as new) — say so instead. - Classify and draft, as in steps 3–4, then re-run once more. Each
finished file moves toapplied/<file>with its receipt and undo
appended. The flag file (**Proposed value:** no change …, orkind: flagfront matter) writes nothing and prints its question every run —
ask the owner that question. - A final re-run changes nothing: no commit, no move; only the flag
question prints.
Kinds come from structure only: optional front matter (kind: landmark|record|flag, letters:, question:) — the family-letters answer
pass will emit it — else the **Proposed value:** field and backtickedgroup/letter ids.
The letter itself (v404, letters-in-the-vault D1)
A family-letters:<collection>/<letter>[,<id>] record — --record or a--from-updates file — files each cited letter ONCE assources/letters/<collection>--<letter>.md before the memo: type: letter
(an external_record, authority third_party_record, sensitivity family,source_id: letters:<collection>--<letter>), the transcript's header fields in the frontmatter
and its body verbatim. The memo gets cites: ["letters:<collection>--<letter>", …]. Filing
prints one line per letter:
✓ Filed letter memory-box-1974/nan-and-pop: sources/letters/memory-box-1974--nan-and-pop.md
letter memory-box-1974/tippets-charles already filed: sources/letters/…
! letter box/x not filed (missing_letter): … → intake: … — the memo is filed without itRelay a not filed line to the owner as it is; the report names the id underletters. The archive is $LIFEHUG_FAMILY_LETTERS_DIR, else configfamily_letters_dir, else ~/Workspace/family-letters.
"Get it from family letters" — the owner names a letter and there is no
memo:
python3 system/lifehug.py intake letter memory-box-1974/nan-and-pop [more ids…] # files, commits, pushes
python3 system/lifehug.py intake letter <id> --no-commit # files; you commitIt files each letter (one already on file is left alone — a record is never
rewritten) and adds the letter to cites on every memo whose record_ref
already names it. It does not classify: the next classify run reads the new
source like any other, and the letter becomes the moment "'s letter
to " dated by the letter itself (basis document).
Many letters, or a refile (v412). When the owner wants a whole
collection, or every letter, filed at a pinned commit of the archive:
python3 system/lifehug.py documents file ~/Workspace/family-letters --all --commit HEAD --dry-run \
--map <owner-id>=self --map <dad-id>=person/dad --scan-url-template 'https://<site>/letters/{id}/scan.pdf'
python3 system/lifehug.py documents file ~/Workspace/family-letters --all --commit <sha> # then commit as printed
python3 system/lifehug.py documents file ~/Workspace/family-letters --ids <collection>/<letter> --commit <sha>It reads the archive through git at the commit (uncommitted edits are never
filed) and uses the same writer as intake letter, so the records are the
same. The --map (which letters/people.yaml id is which vault person) and
the template are remembered. Unchanged transcripts are left alone; a revised
one files a new record that supersedes the old, which stays. Show the
owner the --dry-run counts first; with hundreds of letters, say that the
compile does not yet cap how many letters reach a page (D6).