Skip to content

Releases

oms v0.21.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 08:36
fbd43f0

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=false cannot publish or create a GitHub Release; publication requires a verified oms-v* tag push in a separate privileged job. The npm trusted-publisher transfer hold still applies.

  • Release instructions use the canonical oms setup host and oms setup package commands 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 --json output 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-brain instead of relying on GitHub's redirect from GoBeromsu. 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...

Read more

oms v0.20.6

Choose a tag to compare

@github-actions github-actions released this 01 Oct 06:41

Aggregate

No entries.

Kernel

No entries.

CLI

  • oms doctor contract --fix usage says what it repairs. The doctor and contract usage text said --fix only re-indexes a moved or unindexed vault; it also rebuilds an unreadable index, and the usage now says so. The contract usage also names oms interview as the command that reseals a broken seal, matching the diagnosis's recovery field.

MCP

  • The server instructions no longer call a stale ifMatch a safety refusal. They listed it beside the vault boundary and a tampered contract as something that denies write. A missing or stale ifMatch is a revision precondition: it returns WRITE_IF_MATCH_REQUIRED or the retryable WRITE_TARGET_CHANGED and 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, and setup skills, 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 or oms write whose 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: interview op: seal seals a proposal the owner confirmed. Run oms setup host sync to refresh installed host guidance.

  • Docs and skills say what --fix and ifMatch do. The README, the docs, and the doctor skill now say that oms doctor contract --fix also rebuilds an unreadable index. The architecture page no longer counts a stale ifMatch among the safety refusals; it is a revision precondition that writes nothing. The write skill 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 current status.ts lines.

oms v0.20.5

Choose a tag to compare

@github-actions github-actions released this 30 Sep 16:15

Aggregate

No entries.

Kernel

No entries.

CLI

No entries.

MCP

No entries.

Vendors

  • The Claude marketplace is named after the repository. .claude-plugin/marketplace.json is now oh-my-second-brain, so the plugin id is oms@oh-my-second-brain for Claude Code and Gajae-Code instead of the doubled oms@oms; the plugin and its skills stay oms and /oms:*. To pick up the new name, run claude plugin uninstall oms@oms and claude 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

Choose a tag to compare

@github-actions github-actions released this 30 Sep 12:26

Aggregate

No entries.

Kernel

  • oms doctor contract names oms interview as the recovery command. The recovery field of a contract diagnosis now reads oms interview instead of oms 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 literal oms setup value should match oms interview.

CLI

No entries.

MCP

No entries.

Vendors

No entries.

Assets

No entries.

oms v0.20.3

Choose a tag to compare

@github-actions github-actions released this 30 Sep 11:59

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 write would draft; the hook never drafts, so it lets the write through with the yaml-syntax warning, but it did not record that gap, while MCP write records the same gaps when it saves a note as written. The hook now records them too, so oms doctor sees 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 contract and then resealed at a terminal, without naming oms interview, while the contract-unreadable write warning names oms interview. The skill now names both steps: oms doctor contract diagnoses, and the user reseals with oms interview.

oms v0.20.2

Choose a tag to compare

@github-actions github-actions released this 30 Sep 11:31

Aggregate

No entries.

Kernel

No entries.

CLI

No entries.

MCP

No entries.

Vendors

No entries.

Assets

  • The doctor skill names oms interview for a missing seal. It still sent every broken or missing seal to oms setup, while the contract-open write warning and oms doctor status name oms interview for a missing contract, and oms doctor status names oms doctor contract for 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

Choose a tag to compare

@github-actions github-actions released this 30 Sep 10:53

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 run oms interview instead of carrying only the warning kind. next is absent when there are no warnings, so a clean receipt is unchanged.
  • A vault with no local contract points to oms interview. The contract: none finding and the vaultId present, no local store finding (a synced second machine) and the contract store missing finding now guide to oms interview instead of oms setup, so the write warning, the receipt next and doctor status name the same step for a vault with no contract.
  • An unreadable contract store points to oms doctor contract, not a reseal. The contract store unreadable finding used to suggest oms setup, which could reseal over a tampered store; it now names the same diagnosis as the contract-tampered write warning. The legacy-template finding and the re-ask hint name oms interview.

CLI

  • oms write prints the next command with its warnings. The stderr warnings line ends with Run: <command> (for an unsealed vault, Run: oms interview).
  • Enabling evolution on a vault with no contract names oms interview. EVOLUTION_NO_CONTRACT from the CLI now says to run oms interview first.

MCP

  • write's receipt carries next. It is the command for the receipt's first warning (oms interview for an open contract) and is left out when there are no warnings.

Vendors

No entries.

Assets

  • Host guidance names oms interview for a missing seal. The Claude, Codex and Hermes guidance used to send the user to oms setup for a broken or missing seal. A missing seal is now sealed with oms interview, the command the write warning names, and a broken one is checked with oms doctor contract.
  • The write skill lists the full receipt and tells the agent to relay next. The receipt is described with warnings, fixes and next?, and the denial with its real status, refusals and violations shape. It no longer says an unreadable contract denies writes: an unsealed or unreadable contract saves the note with a warning that names oms interview, and only a tampered contract is denied, pending oms doctor contract.

oms v0.20.0

Choose a tag to compare

@github-actions github-actions released this 30 Sep 09:52

Aggregate

  • ip-address no longer carries its <=10.5.0 SSRF advisories. npm run audit started failing again on the transitive @modelcontextprotocol/sdk → express-rate-limit → ip-address chain (GHSA-rpw4-54j3-4h4q, GHSA-2vr4-cq9g-pvrc). npm audit fix (no --force) resolved it to 10.7.2, still within express-rate-limit's own ^10.2.0 range, so only package-lock.json changed — no package.json edit or overrides entry was needed. npm run audit reports 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.ts is the only path that seals an evolved candidate; the only other product caller of sealContract is 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 removed required, as classified by mutation-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, so evolve issues nothing (EVOLUTION_STAGE2_REFUSED) and the router and the autonomous seal-gate refuse it and journal request.rejected. Stage 3 is a 2-of-3 quorum of evaluator verdicts from an injected VerdictProvider, waiting for all three bound verdicts, and its reject is effective: the same request never seals on a rerun. A provider without subagents is EVALUATOR_CONSENSUS_UNAVAILABLE before anything is asked or written. evolve requires 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 records quorum: "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 through human-approval.ts and seal-gate-human.ts, which seal through the same gate. revert.ts proposes 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 to awaiting-human for the owner to approve at oms setup; a verdict on it is refused with EVOLUTION_REQUEST_CLOSED, and the owner's seal records the proposer as owner. 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. The maker-unknown discard applies only to evolve requests. The judge is unchanged.
  • doctor runs the evolution ops and reports evolution in status. src/kernel/doctor/evolution-ops.ts runs evolve, evolve-verdict, revert-propose and reclaim-evolution-lock on 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 throws EVOLUTION_POSTCONDITION_FAILED, or EVOLUTION_POSTCONDITION_FAILED_AFTER_SEAL naming the sealed digest and generation when the seal already happened. reclaim-evolution-lock needs the owner at a terminal. src/kernel/doctor/evolution-status.ts gives doctor status an evolution section: journal counters, requests awaiting the owner, the autonomous budget left today and this week, and whether the lineage has a gap, and quorum: "host-attested", how an autonomous seal's quorum is attested. It is read-only and null for an unsealed vault.
  • The seal boundary is enforced. test/architecture/write-evolution-boundary.test.ts now fails when a new module names sealContract, a test fixture is reachable from an entrypoint, anything but src/cli/evolution-approve.ts imports the approval modules, the approval module reads stdin or seals, the maker or evaluator stages reach the write kernel, or kernel/contract imports kernel/evolution. Non-literal dynamic imports in src/ fail the gate.
  • An empty or comment-only frontmatter block is empty frontmatter, not malformed YAML. parseNote now reads --- followed directly by ---, or a block that holds only comments, as a note with no properties instead of a yaml-syntax draft. 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, and oms doctor audit no longer reports these notes as yaml-syntax. The block closes at the first fence, so in ---, ---, k: v, --- the k: v line is body text, as Obsidian reads it; a test pins this.
  • A discarded coerce pass no longer uses up a fix pass. resolveTiers in src/kernel/write/ambiguity.ts counts 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 [...]), a date (YYYY-MM-DD or {{date}}) or a datetime (YYYY-MM-DDTHH:mm or its {{date:...}} format) when its value clearly is one, and as text otherwise 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 else text, so a vault whose status appears only in templates is asked about it; templates themselves are still never asked about or sealed. oms doctor contract adds the finding template-folder-unset when an older generation sealed templates but .oms/settings.json names no templateFolder, 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.json and an optional declined.json ({version: 2, folders, properties}); no templates/ directory is written. Version 1 and 2 generations stay readable permanently and their digests are unchanged: their templates are projected into view.legacy.templates on read and never persisted. VaultContract no longer carries templates (the old shape is LegacyTemplateContract), the judge never enforces them, and template drift detection (drift.ts) is removed. oms doctor contract reports legacy-template-constraints-ignored: N for 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 from templateFolder instead (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.ts fixes 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, decideWrite returns it as fixedContent, and each fix is recorded as a fixed gap whose wanted is 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 a kept gap. 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...
Read more

oms v0.19.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 16:26

Aggregate

  • Upgrading from 0.18: run oms setup host sync first. 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 hidden hook, and the five MCP tools become write, search, interview, and doctor. 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; write now runs one pipeline that conforms template variables and headings mechanically, judges, writes atomically with an optional ifMatch revision, and updates the keyword index in the same call while queueing vectors for oms 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. runWritePipeline in src/kernel/write/pipeline.ts replaces verified-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 in requiredProperties, 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 needs ifMatch, the sha256: revision of its current bytes; without it the outcome is if-match-required, and a revision that no longer matches, a note that vanished, or an ifMatch sent for a note that does not exist (absent, retried without ifMatch to create it) is a retryable retry. check stops after the judge and reports the frame, the revision and the violations without touching disk. A written note returns the receipt built by receipt.ts, {ok, path, revision, contractRevision, index: {keyword, vector}, conformed, missingDefaults}, and writePayload in payload.ts shapes every outcome for both surfaces. src/kernel/engine/index-update.ts replaces the note's keyword rows in an existing engine store in the same call and queues its vectors in engine_dirty; it never creates a store, and doctor sync-embeddings drains the queue, reporting queue: {drained, pending}.

  • TemplateContract.meaning records 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.ts owns <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 with O_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 with O_NOFOLLOW | O_NONBLOCK and checked through its handle to be a regular 0600 file; a symlink, FIFO, socket or foreign-owned entry is refused with STATE_DIR_UNSAFE and left exactly as found, without blocking; the message names the fix (chmod go-w <path> for a shared-writable entry, chown or removal for one owned by another user). Two appends that create the directory at the same moment no longer fail with EEXIST: the one that loses the race checks the directory the other created. interview-log.ts appends asked, answered, proposed, sealed and abandoned events as JSON lines. Appends are serialized within a process only, not across processes: seq is one more than the highest in the file, so two processes appending at once may write the same seq, and readers order events by line, not by seq. A truncated or malformed line is skipped and kept, and contractDoctor reports it read-only as interviewLog: {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>.state when the seal mints the id, keeping any events already there. interview-resume.ts replays 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. runInterview takes a record hook, 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.json first and then records sealed best-effort: a failed record leaves the seal in place and returns the warning INTERVIEW_LOG_UNRECORDED.

  • Deny guidance and the surface registry use the 0.19 spellings. GUIDANCE now names oms doctor contract, oms doctor contract --fix, oms doctor status, oms setup host sync, and oms setup. The harness registry lists six skills, four MCP tools, and seven CLI families with hook hidden. writePayload in src/kernel/write/payload.ts builds the one payload shape that MCP write and oms write both print, so the two surfaces cannot drift.

  • readExact reads one note by its vault-relative path without the engine. src/kernel/search/read-exact.ts matches 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.md read 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 a sha256: revision of the bytes, and imports nothing from the engine or a native backend; test/architecture/read-exact-isolation.test.ts walks its import graph to keep it that way. src/kernel/text/nfc.ts provides the toNfc and nfcEquals helpers 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.md and a__b/meeting.md no longer claim the same name and neither becomes unsealable; rekeySealedTemplates uses 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 dynamic import() 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 observedHash that is not the source's current digest is refused, and the...

Read more

oms v0.18.3

Choose a tag to compare

@github-actions github-actions released this 26 Sep 06:33

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-* with SKILL_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.