Repository navigation
Releases
oms v0.21.0
Aggregate
-
Release rehearsals use a read-only verification job with no OIDC grant and never invoke npm publish, including dry runs. Manual dispatch on a tag or with
rehearsal=falsecannot publish or create a GitHub Release; publication requires a verifiedoms-v*tag push in a separate privileged job. The npm trusted-publisher transfer hold still applies. -
Release instructions use the canonical
oms setup hostandoms setup packagecommands and describe the six skills and four MCP tools verified by the artifact rehearsal, so operators can follow the documented upgrade steps with the current package. -
Packaging and documentation checks accept npm 12's package-name-keyed
pack --jsonoutput alongside npm 10/11 arrays. A shared strict parser rejects errors, unexpected packages, multi-package reports, and malformed file manifests instead of silently skipping checks. -
Repository metadata follows the GitHub ownership transfer. Package, issue, installer, attribution, measurement, release-check, and release-process links now point directly at
Xia-Ataraxia/oh-my-second-braininstead of relying on GitHub's redirect fromGoBeromsu. The repository history, releases, tags, package name, marketplace name, versions, and author attribution are unchanged. npm trusted-publisher rebinding remains a separately approved registry action; no publish or tag is part of this migration.
Kernel
-
Default public facet summaries now bound payload bytes as well as cardinality: at most 20 entries and 32 KiB of serialized array JSON including the two-space CLI/MCP indentation, omitting keys or values over 512 UTF-8 bytes without changing their identities. Warnings disclose retained/total counts and byte-limit omissions; complete collection aggregation, hit ranking, counts and pagination remain unchanged. This bounds the facet array, not the whole response or aggregation memory.
-
Temporary lexical spills and read-only snapshots retain the canonical directory's device/inode identity and recheck ownership before reuse, copying, and cleanup. Missing, replaced, symlinked, or unverifiable directories are left untouched with a bounded residue diagnostic; cleanup failures preserve the original operation error. These observations detect replacement but do not provide an atomic boundary against ongoing same-user tampering.
-
Observed-only frontmatter filters and discovery capture current metadata without seeding detached lexical storage or chunking Markdown. Warm requests reuse the existing parsed projection cache and private EAV backing. A later lexical or mixed query reconciles the complete canonical chunk corpus, while concurrent upgrades wait for joined metadata selectors to finish; source witnesses, cursor validation, memory budgets and read-only persistence behavior are preserved.
-
Detached lexical reconciliation skips clearing a document whose stored chunk set is already empty. Empty FTS deletes flush pending terms even without matching rows; avoiding them lets fresh notes share the intended bounded native batch while preserving existing-note cleanup and rollback.
-
Live lexical capture groups disk-backed document updates into bounded synchronous transactions. The queue owns serialized chunks and source evidence, including title/heading metadata, and flushes residual records before retrieval. Dedicated reconciliation reuses its outer rollback boundary without redundant FTS savepoints; ordinary store methods retain independent atomicity. In-memory capture still commits and checks the spill budget one document at a time.
-
Detached live lexical captures update each note's chunks and verified source evidence in one synchronous private transaction, reducing separate commits during cold corpus construction. A failed source publication rolls back that note's lexical changes. Persistent stores, SQLite durability settings, native ranking, memory budgets and final source validation keep their existing behavior.
-
Live lexical capture shares one canonical frontmatter parse between its compact metadata projection and chunk title extraction. Malformed metadata diagnostics, title fallback, raw embedding text and copied projection values keep their existing semantics; unchanged warm notes still skip parsing.
-
Chunking counts each line's script-aware token weight once and carries the exact weight through overlap, avoiding repeated scans of growing buffers on short-line notes. Canonical chunk text, title, heading paths, ordinals and digests remain unchanged; cold live search still captures the full corpus and performs its existing freshness checks.
-
Automatic maintenance ignores excluded editor housekeeping watch hints while retaining known exclusion settings and their directory replacements. Uppercase Markdown hints remain incremental, and unsafe or uncertain paths still request complete reconciliation.
-
Automatic full maintenance only loads an already installed native embedding backend; missing binaries fail with setup guidance instead of downloading or building llama.cpp in the background. Explicit provider callers retain their existing policy.
-
Explicit automatic maintenance reuses the existing index and revisioned queue with bounded scheduling, complete-scan recovery and separate conservative process ownership. Watch hints never authorize mass deletion; cancelled or superseded embedding jobs cannot commit. The feature stays off unless a server invocation enables it, and existing source/target/model checks remain authoritative.
-
Warm live lexical sessions keep their complete private corpus across persistent index writes, vector syncs, rebuilds, and index removal or replacement. Each query still refreshes current Markdown and validates returned sources; incomplete captures and changed or unknown vault identities retain conservative bootstrap checks. Private freshness never certifies persistent/vector synchronization, and searches still leave those stores untouched.
-
Late embedding jobs validate their captured revision and model before initializing an existing store. Preflight, schema initialization, and publication share one connection and transaction, so replaced stores and cancelled legacy migrations remain unchanged when a job is rejected.
-
Background embedding maintenance completes already-embedded queue entries only after checking real vector coverage, and repairs verified clean chunks whose vectors are missing. Legacy revision-less entries can be upgraded safely, preventing repeated stale retries after interrupted queue housekeeping. Pending-only paths remain visible to complete scans so excluded or deleted notes cannot strand orphaned work.
-
Short index writers serialize stale-lock recovery with immutable per-attempt owner records, closing a race that could temporarily move a live successor and admit another writer. All concurrent writers must use the upgraded protocol; the legacy lock remains visible but cannot fence an already-running old reclaimer. Unreadable or malformed legacy owner records now fail closed instead of being reclaimed or retried indefinitely.
-
Per-note write maintenance publishes lexical chunks, source evidence, and a revisioned embedding queue in one SQLite transaction. Background embedding results can commit only against the same source, chunks, model, and active owner; edits, deletions, or cancellation leave newer work intact. Explicit embedding sync also repairs missing vectors left by interrupted legacy lexical updates and retains pending work through lexical-only passes.
-
Observed value facets include a directly reusable, JSON-safe exact typed selection. Selecting a date, date-looking string, numeric timestamp, boolean or string now reproduces its distinct-note count within an unchanged discovery scope, without changing declared-axis or legacy comparison behavior. Exact date selectors require canonical ISO strings rather than permissive date coercion.
-
Ordinary live refresh prunes obsolete projection backing without invalidating unchanged observed-field rows. The next explicit observed query removes deleted/excluded canonical metadata and adds renamed notes through the existing authoritative snapshot reconciliation, avoiding a whole-corpus EAV rewrite while retaining cursor invalidation and current-source checks.
-
Live lexical projection overflow now reuses the original compact parsed document from versioned binary rows in the existing session-private axis store. Unchanged notes beyond the object-cache budget no longer require repeated body reads or YAML parsing; edits and missing/incompatible rows are recaptured, deleted/excluded rows are removed, and ordinary declared-axis/facet behavior remains unchanged. The same private spill owner bounds retained SQLite pages and cleans up failed refreshes after readers drain.
-
Explicit observed frontmatter queries now filter the same current-byte native FTS snapshot before candidate limits. Scalar/list predicates, bounded key/value discovery, cross-session cursors, and source-race rejection work without a sealed field declaration; existing declared axes retain their semantics. Dense observations spill the existing EAV repository to disposable session-private storage, never a new persistent index.
-
The existing axis-observation repository gains an in-memory observed-field query foundation: shared scalar/list and range operators, parameterized pre-limit candidate intersection, current-source reconciliation, and bounded key/value discovery with distinct-note counts and snapshot-bound cursors. Declared typed axes keep their existing behavior, and cyclic YAML lists no longer recurse forever in the EAV importer.
-
Hash-prefixed native document IDs resolve currently admitted Markdown paths, so new or renamed live-search hits can be opened before an explicit index sync. The reader checks current exclusions and captures confined, non-symlink source bytes without changing model/backend selection.
-
Live lexical sessions pin c...
oms v0.20.6
Aggregate
No entries.
Kernel
No entries.
CLI
oms doctor contract --fixusage says what it repairs. Thedoctorand contract usage text said--fixonly re-indexes a moved or unindexed vault; it also rebuilds an unreadable index, and the usage now says so. The contract usage also namesoms interviewas the command that reseals a broken seal, matching the diagnosis'srecoveryfield.
MCP
- The server instructions no longer call a stale
ifMatcha safety refusal. They listed it beside the vault boundary and a tampered contract as something that denieswrite. A missing or staleifMatchis a revision precondition: it returnsWRITE_IF_MATCH_REQUIREDor the retryableWRITE_TARGET_CHANGEDand writes nothing, and the safety list now also names unsupported input.
Vendors
No entries.
Assets
-
Skills and host guidance now say that contract findings warn instead of deny. The
write,distill, andsetupskills, the Claude, Codex, and Hermes host guidance, and the README and docs had kept saying that a note breaking the contract is denied. Since the contract became warn-first, such a note is saved with each finding as a{field, kind}warning and one guidance command; only a safety refusal (a path outside the vault, a control or unsafe path, unsupported input, a tampered contract) denies, and in a sealed vault a note written through MCP oroms writewhose frontmatter does not parse may be kept as a draft. Agents reading the old wording stopped and asked after a write that had already succeeded. The README also no longer says MCP cannot seal:interviewop: sealseals a proposal the owner confirmed. Runoms setup host syncto refresh installed host guidance. -
Docs and skills say what
--fixandifMatchdo. The README, the docs, and thedoctorskill now say thatoms doctor contract --fixalso rebuilds an unreadable index. The architecture page no longer counts a staleifMatchamong the safety refusals; it is a revision precondition that writes nothing. Thewriteskill says that among contract states only a tampered contract denies, the 0.19 migration guide notes that a contract finding has warned since 0.20, and the harness architecture page cites the currentstatus.tslines.
oms v0.20.5
Aggregate
No entries.
Kernel
No entries.
CLI
No entries.
MCP
No entries.
Vendors
- The Claude marketplace is named after the repository.
.claude-plugin/marketplace.jsonis nowoh-my-second-brain, so the plugin id isoms@oh-my-second-brainfor Claude Code and Gajae-Code instead of the doubledoms@oms; the plugin and its skills stayomsand/oms:*. To pick up the new name, runclaude plugin uninstall oms@omsandclaude plugin marketplace remove oms, then install again. The README now credits Gajae Code through the acknowledgements, and the Gajae-Code install command lives in the host asset guide.
Assets
No entries.
oms v0.20.4
Aggregate
No entries.
Kernel
oms doctor contractnamesoms interviewas the recovery command. Therecoveryfield of a contract diagnosis now readsoms interviewinstead ofoms setup, so the diagnosis, the write warnings, the interview refusal and the doctor skill all name the same reseal command. Both commands run the same terminal interview, so recovery itself is unchanged; an agent that matched on the literaloms setupvalue should matchoms interview.
CLI
No entries.
MCP
No entries.
Vendors
No entries.
Assets
No entries.
oms v0.20.3
Aggregate
No entries.
Kernel
No entries.
CLI
No entries.
MCP
No entries.
Vendors
- The Claude hook records malformed frontmatter as a kept gap. A write whose frontmatter does not parse is one MCP
writewould draft; the hook never drafts, so it lets the write through with theyaml-syntaxwarning, but it did not record that gap, while MCPwriterecords the same gaps when it saves a note as written. The hook now records them too, sooms doctorsees the same gaps whichever path wrote the note.
Assets
- The doctor skill names the reseal command for a broken seal. It said a tampered or unreadable contract store is diagnosed with
oms doctor contractand then resealed at a terminal, without namingoms interview, while thecontract-unreadablewrite warning namesoms interview. The skill now names both steps:oms doctor contractdiagnoses, and the user reseals withoms interview.
oms v0.20.2
Aggregate
No entries.
Kernel
No entries.
CLI
No entries.
MCP
No entries.
Vendors
No entries.
Assets
- The doctor skill names
oms interviewfor a missing seal. It still sent every broken or missing seal tooms setup, while thecontract-openwrite warning andoms doctor statusnameoms interviewfor a missing contract, andoms doctor statusnamesoms doctor contractfor a tampered or unreadable store. A Hermes trial on 0.20.1 read the two routes as conflicting; the skill now matches the receipt.
oms v0.20.1
Aggregate
No entries.
Kernel
- A write receipt with warnings names the command that resolves them. The receipt gains
next, the guidance for its first warning, so a note saved into a vault with no sealed contract (contract-open) now says to runoms interviewinstead of carrying only the warning kind.nextis absent when there are no warnings, so a clean receipt is unchanged. - A vault with no local contract points to
oms interview. Thecontract: nonefinding and thevaultId present, no local storefinding (a synced second machine) and thecontract store missingfinding now guide tooms interviewinstead ofoms setup, so the write warning, the receiptnextanddoctor statusname the same step for a vault with no contract. - An unreadable contract store points to
oms doctor contract, not a reseal. Thecontract store unreadablefinding used to suggestoms setup, which could reseal over a tampered store; it now names the same diagnosis as thecontract-tamperedwrite warning. The legacy-template finding and the re-ask hint nameoms interview.
CLI
oms writeprints the next command with its warnings. The stderr warnings line ends withRun: <command>(for an unsealed vault,Run: oms interview).- Enabling evolution on a vault with no contract names
oms interview.EVOLUTION_NO_CONTRACTfrom the CLI now says to runoms interviewfirst.
MCP
write's receipt carriesnext. It is the command for the receipt's first warning (oms interviewfor an open contract) and is left out when there are no warnings.
Vendors
No entries.
Assets
- Host guidance names
oms interviewfor a missing seal. The Claude, Codex and Hermes guidance used to send the user tooms setupfor a broken or missing seal. A missing seal is now sealed withoms interview, the command the write warning names, and a broken one is checked withoms doctor contract. - The write skill lists the full receipt and tells the agent to relay
next. The receipt is described withwarnings,fixesandnext?, and the denial with its realstatus,refusalsandviolationsshape. It no longer says an unreadable contract denies writes: an unsealed or unreadable contract saves the note with a warning that namesoms interview, and only a tampered contract is denied, pendingoms doctor contract.
oms v0.20.0
Aggregate
ip-addressno longer carries its<=10.5.0SSRF advisories.npm run auditstarted failing again on the transitive@modelcontextprotocol/sdk→express-rate-limit→ip-addresschain (GHSA-rpw4-54j3-4h4q, GHSA-2vr4-cq9g-pvrc).npm audit fix(no--force) resolved it to10.7.2, still withinexpress-rate-limit's own^10.2.0range, so onlypackage-lock.jsonchanged — nopackage.jsonedit oroverridesentry was needed.npm run auditreports zero vulnerabilities again.
Kernel
- The vault contract can evolve from its write gaps, and only one seal-gate may seal it.
src/kernel/evolution/turns the open gaps into one maker-drafted evolution request (evolve.ts,maker.ts) with a pinned candidate, a nonce and three evaluator slots, held under an evolution lock with its own journal (events.ts).seal-gate.tsis the only path that seals an evolved candidate; the only other product caller ofsealContractis the interview. Stage 1 (stage-mechanical.ts) judges the vault's existing notes against the candidate: any new refusal rejects it, and the warning delta is its score, reported on every request. A candidate that raises warnings, or that loosens the contract (an added allowed value or folder, a widened type, a removedrequired, as classified bymutation-direction.ts), waits for the owner. Stage 2 (stage-semantic.ts) is a hard gate too: a touched entry whose meaning overlaps an existing one (similarity 0.9 or more) or a candidate that drifts more than 0.3 from the first sealed generation is rejected, soevolveissues nothing (EVOLUTION_STAGE2_REFUSED) and the router and the autonomous seal-gate refuse it and journalrequest.rejected. Stage 3 is a 2-of-3 quorum of evaluator verdicts from an injectedVerdictProvider, waiting for all three bound verdicts, and its reject is effective: the same request never seals on a rerun. A provider without subagents isEVALUATOR_CONSENSUS_UNAVAILABLEbefore anything is asked or written.evolverequires the maker's session id (EVOLUTION_MAKER_SESSION_REQUIRED), and a verdict whose session repeats another evaluator's or the maker's is discarded. The quorum is host-attested: OMS cannot verify that the evaluators were independent subagents, so autonomy is off by default and an autonomous seal recordsquorum: "host-attested"in its journal event and lineage event. An autonomous seal needs the opt-in policy (policy.ts, off by default, turned on only interactively, limits of 1 a day and 3 a week that can only be lowered), the quorum, a warning delta of 0 or less (a negative delta qualifies) and the rate limit (rate-limit.ts). The owner decides approve or reject throughhuman-approval.tsandseal-gate-human.ts, which seal through the same gate.revert.tsproposes a kept generation as a new forward candidate, read only from its snapshot and projected to the version 3 form. A revert always requires owner approval: it has no maker, so no host quorum can bind to it, and every revert (tightening, neutral or loosening, with autonomy on or off) goes toawaiting-humanfor the owner to approve atoms setup; a verdict on it is refused withEVOLUTION_REQUEST_CLOSED, and the owner's seal records the proposer asowner. Stage 1 and stage 2 both run when a revert is proposed, so a revert that adds a refusal (EVOLUTION_REVERT_REFUSED) or overlaps or drifts past 0.3 (EVOLUTION_STAGE2_REFUSED) proposes nothing. Themaker-unknowndiscard applies only toevolverequests. The judge is unchanged. doctorruns the evolution ops and reports evolution in status.src/kernel/doctor/evolution-ops.tsrunsevolve,evolve-verdict,revert-proposeandreclaim-evolution-lockon a verified target, each checking a postcondition read back from the store (the request state, the pinned candidate digest, the slot used exactly once, the linked generation unmoved or equal to the sealed candidate, the lock gone). A postcondition that does not hold throwsEVOLUTION_POSTCONDITION_FAILED, orEVOLUTION_POSTCONDITION_FAILED_AFTER_SEALnaming the sealed digest and generation when the seal already happened.reclaim-evolution-lockneeds the owner at a terminal.src/kernel/doctor/evolution-status.tsgivesdoctor statusanevolutionsection: journal counters, requests awaiting the owner, the autonomous budget left today and this week, and whether the lineage has a gap, andquorum: "host-attested", how an autonomous seal's quorum is attested. It is read-only andnullfor an unsealed vault.- The seal boundary is enforced.
test/architecture/write-evolution-boundary.test.tsnow fails when a new module namessealContract, a test fixture is reachable from an entrypoint, anything butsrc/cli/evolution-approve.tsimports the approval modules, the approval module reads stdin or seals, the maker or evaluator stages reach the write kernel, orkernel/contractimportskernel/evolution. Non-literal dynamic imports insrc/fail the gate. - An empty or comment-only frontmatter block is empty frontmatter, not malformed YAML.
parseNotenow reads---followed directly by---, or a block that holds only comments, as a note with no properties instead of ayaml-syntaxdraft. A missing required property whose rule fixes its value, a new note's date defaults and a template's frontmatter defaults are now filled into such a block, and the inserted lines sit on their own line before the closing fence. Other readers change with it: building the axes store no longer fails on such a note, a live template whose frontmatter is---then---now loads and can add a template choice for its folder, andoms doctor auditno longer reports these notes asyaml-syntax. The block closes at the first fence, so in---,---,k: v,---thek: vline is body text, as Obsidian reads it; a test pins this. - A discarded coerce pass no longer uses up a fix pass.
resolveTiersinsrc/kernel/write/ambiguity.tscounts only accepted passes against its three fix passes, and a separate hard cap of twelve attempts still bounds the loop. - The interview types a template key Obsidian has not typed from its value. A key set only by the live templates is offered as a
list(a-item block or[...]), adate(YYYY-MM-DDor{{date}}) or adatetime(YYYY-MM-DDTHH:mmor its{{date:...}}format) when its value clearly is one, and astextotherwise or when templates disagree. An Obsidian property type still wins. - Scaffolded headings keep the note's line endings. Conform appends a template's missing headings to a CRLF note with CRLF, not LF.
- Scaffolding skips Templater tags, and the interview offers the keys templates set. Conform never runs Templater, so a template value or heading that holds a
<% ... %>tag is left out of a new note, the same as an unfilled{{...}}, instead of being saved as literal tag text. A multi-line template value is inserted with the note's own line endings, so a CRLF note stays CRLF. The interview now also offers each frontmatter key the templates in the template folder set as a property to register, typed as Obsidian types it or elsetext, so a vault whosestatusappears only in templates is asked about it; templates themselves are still never asked about or sealed.oms doctor contractadds the findingtemplate-folder-unsetwhen an older generation sealed templates but.oms/settings.jsonnames notemplateFolder, suggesting the folder those templates share; it writes nothing. - New contract generations no longer store templates; older generations still load and their template constraints are reported, not enforced. The store now writes manifest version 3, which lists only
folders.json,properties.jsonand an optionaldeclined.json({version: 2, folders, properties}); notemplates/directory is written. Version 1 and 2 generations stay readable permanently and their digests are unchanged: their templates are projected intoview.legacy.templateson read and never persisted.VaultContractno longer carries templates (the old shape isLegacyTemplateContract), the judge never enforces them, and template drift detection (drift.ts) is removed.oms doctor contractreportslegacy-template-constraints-ignored: Nfor a head that still carries them, and a revert or reseal writes a new version 3 head rather than rewriting an old generation. Neither the judge nor the write decision reads an older generation's templates: their required properties, narrowed rules and required headings no longer shape a verdict, a fix or a contradiction. A newly sealed vault carries no templates; templates scaffold fromtemplateFolderinstead (see below). - Unknown keys and out-of-rule values are saved as written and recorded; lossless type and spelling fixes are applied with the original kept in the ledger.
src/kernel/write/coerce.tsfixes a new warning only when the contract reads the value the same way: a number or checkbox written as a string, a scalar for a list, a midnight datetime for a date, a number for text, an allowed value that differs only in Unicode form, spacing or case and matches exactly one allowed value, and a missing property whose rule fixes its value (or, on a new note, a date or datetime default). The fixed note is judged again,decideWritereturns it asfixedContent, and each fix is recorded as afixedgap whosewantedis the value as written. Every other new warning, including an unknown key, an unmatched allowed value, a pattern, range or count miss, and an unregistered folder, is saved as written and recorded as akeptgap. Only frontmatter that does not parse is kept as a draft. The key-dropping repair is removed (DROPPABLE,droppableKeys,dropFrontmatterKeys,requiredBy), so nothing a note says is silently deleted. Coerce fills a required property whose rule fixes its value when it is missing, an...
oms v0.19.0
Aggregate
- Upgrading from 0.18: run
oms setup host syncfirst. Installed host assets (the Claude guard hook, skills, and MCP wiring) still point at the 0.18 surface until they are re-synced. Then read Migrating to 0.19 for the full command map. - Breaking: OMS is organised around search, interview, and write. The fourteen CLI families collapse into
search,interview,write,setup,doctor,serve, and the hiddenhook, and the five MCP tools becomewrite,search,interview, anddoctor. A removed command exits 1 and names its replacement rather than aliasing it. The judge, the sealed contract, and the verified-target rules are unchanged;writenow runs one pipeline that conforms template variables and headings mechanically, judges, writes atomically with an optionalifMatchrevision, and updates the keyword index in the same call while queueing vectors foroms doctor sync-embeddings. See the layer changelogs for details. - The contract stops guessing what a template declares. OMS used to parse template text to decide which questions the seal interview asks, substituting an in-band sentinel token for each Templater variable so the rest would still parse as YAML. Real templates broke that: four of this vault's templates put a variable where YAML expects a key, and a Templater JavaScript template with no frontmatter passed silently as declaring nothing while it really declares ten properties and four headings. Reading a template is now the agent's job and deriving the contract stays the machine's: the agent submits an interpretation, OMS verifies it against the sources it enumerated and the digests it computed itself, the owner confirms the interpretation before it decides a single question, and every sealed value still comes only from the owner's answers.
Kernel
-
One write pipeline frames, conforms, judges, writes and indexes a note.
runWritePipelineinsrc/kernel/write/pipeline.tsreplacesverified-write: it admits and resolves the target, builds the frame the note is judged in (frame.ts: sealed folder meaning, properties, the chosen template and its defaults), applies only mechanical fixes (conform.ts:{{title}},{{date}}and{{time}}variables, date and datetime defaults on a new note, and the chosen template's missing headings), then runs the unchanged judge. Conform adds only that mechanical skeleton and those defaults: it never changes a value and never supplies a property the contract or a template requires (a date default is skipped for any name a template lists inrequiredProperties, every template's when none is chosen), so a missing required property is still refused. The heading skeleton does, by design, satisfy a template's required headings, and inserted lines keep the note's CRLF or LF line endings. Overwriting an existing note needsifMatch, thesha256:revision of its current bytes; without it the outcome isif-match-required, and a revision that no longer matches, a note that vanished, or anifMatchsent for a note that does not exist (absent, retried withoutifMatchto create it) is a retryableretry.checkstops after the judge and reports the frame, the revision and the violations without touching disk. A written note returns the receipt built byreceipt.ts,{ok, path, revision, contractRevision, index: {keyword, vector}, conformed, missingDefaults}, andwritePayloadinpayload.tsshapes every outcome for both surfaces.src/kernel/engine/index-update.tsreplaces the note's keyword rows in an existing engine store in the same call and queues its vectors inengine_dirty; it never creates a store, and doctorsync-embeddingsdrains the queue, reportingqueue: {drained, pending}. -
TemplateContract.meaningrecords what a template is for, and the seal manifest is version 2. The field is optional; a version 1 manifest still reads, so an existing seal needs no reseal. -
The interview keeps an append-only log beside the contract store, so an interrupted interview continues where it stopped.
src/kernel/contract/state-dir.tsowns<root>/.<id>.state/{interview,evolution,generations}: it sits next to the<id>link, never inside a.<id>.<seq>generation, and matches none of the names a seal collects, so a seal neither lists nor removes it and losing the link leaves the log in place. Every component is lstat-checked before and after creation (not a symlink, a directory owned by this user, not group- or other-writable), directories are created 0700 by chmod through a handle opened withO_DIRECTORY | O_NOFOLLOW, so a directory swapped for a symlink is refused rather than having its target's mode changed, and a file is opened withO_NOFOLLOW | O_NONBLOCKand checked through its handle to be a regular 0600 file; a symlink, FIFO, socket or foreign-owned entry is refused withSTATE_DIR_UNSAFEand left exactly as found, without blocking; the message names the fix (chmod go-w <path>for a shared-writable entry,chownor removal for one owned by another user). Two appends that create the directory at the same moment no longer fail withEEXIST: the one that loses the race checks the directory the other created.interview-log.tsappendsasked,answered,proposed,sealedandabandonedevents as JSON lines. Appends are serialized within a process only, not across processes:seqis one more than the highest in the file, so two processes appending at once may write the sameseq, and readers order events by line, not byseq. A truncated or malformed line is skipped and kept, andcontractDoctorreports it read-only asinterviewLog: {corrupt, pendingCorrupt, unreadable}with line numbers. Before the first seal a vault has no id, and the interview writes nothing into it: its log lives under a pending key derived from the vault's real path,.pending-<sha256>.state, and moves into.<id>.statewhen the seal mints the id, keeping any events already there.interview-resume.tsreplays the answers logged since the last seal or restart, but only while the question still reads the same (its digest covers the prompt, options and default), and reports the rest as drift so they are asked again. An interrupted run that is resumed seals byte-for-byte the contract an uninterrupted run seals.runInterviewtakes arecordhook, records each question as the terminal asks it (the MCP tool, which lists questions, does not) and the proposal digest before the seal question. After the seal it persists the template folder to.oms/settings.jsonfirst and then recordssealedbest-effort: a failed record leaves the seal in place and returns the warningINTERVIEW_LOG_UNRECORDED. -
Deny guidance and the surface registry use the 0.19 spellings.
GUIDANCEnow namesoms doctor contract,oms doctor contract --fix,oms doctor status,oms setup host sync, andoms setup. The harness registry lists six skills, four MCP tools, and seven CLI families withhookhidden.writePayloadinsrc/kernel/write/payload.tsbuilds the one payload shape that MCPwriteandoms writeboth print, so the two surfaces cannot drift. -
readExactreads one note by its vault-relative path without the engine.src/kernel/search/read-exact.tsmatches each path segment against the directory listing (exact spelling, then NFC, then a single NFC-equal entry), so a note saved with an NFD Hangul name is found from its NFC spelling on every filesystem, not only where APFS happens to fold the two. It refuses.., absolute paths, a path ending in a separator, and symlinks that resolve outside the vault, while names that merely begin with two dots such as..notes/x.mdread normally. Each directory is resolved and checked against the vault before it is listed, so a symlink out of the vault reports an escape whether or not the name behind it exists. The note is opened once, without following a final symlink and without blocking, and that one handle is checked to be a regular file and read, so a FIFO is refused as not a file instead of hanging. It names a missing note plainly, returns the on-disk spelling as a POSIX path and asha256:revision of the bytes, and imports nothing from the engine or a native backend;test/architecture/read-exact-isolation.test.tswalks its import graph to keep it that way.src/kernel/text/nfc.tsprovides thetoNfcandnfcEqualshelpers it uses. -
A seal refuses when the template sources moved under the interview, and folder scope is injective. The seal re-enumerates the template sources under the seal lock, before anything is written, and compares them with the snapshot the questions were built from; an added, removed or changed source aborts the seal with nothing sealed, instead of sealing stale bytes and reporting drift afterwards. A scoped template name now escapes each path component, so
a/b/meeting.mdanda__b/meeting.mdno longer claim the same name and neither becomes unsealable;rekeySealedTemplatesuses the same encoding and is idempotent. The condition-4 gate that keeps the write-checking judge away from the interpretation modules walks the TypeScript AST instead of one import regex, so a side-effect import, a re-export barrel and a literal dynamicimport()are all followed. -
OMS no longer reads template text; an agent's interpretation is the input. The deterministic pre-analysis is gone, along with the in-band sentinel token it substituted for each template variable: a template can be Templater JavaScript, can put a variable where YAML expects a key, and can carry no frontmatter at all, so no mechanical reading of it was trustworthy. The interview now enumerates the template sources, computes each one's digest, and takes a submitted interpretation of each; a submission that names an unknown source, omits one, or carries an
observedHashthat is not the source's current digest is refused, and the...
oms v0.18.3
Aggregate
- Ships the Hermes skill namespace from 0.18.2. The 0.18.2 tag failed its release check on a flaky test and was never published to npm, so 0.18.3 is the first published release where Hermes installs the OMS skills as
oms-*withSKILL_CAPABILITY_GUIDE.md(see 0.18.2 below). The read-only engine store tests now use a private temporary directory, so snapshot directories from parallel test files no longer break the check.
Kernel
No entries.
CLI
No entries.
MCP
No entries.
Vendors
No entries.
Assets
No entries.