@hraness/oh 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +598 -0
  3. package/dist/canonical.d.ts +32 -0
  4. package/dist/canonical.d.ts.map +1 -0
  5. package/dist/cli.d.ts +4 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +3419 -0
  8. package/dist/contract.d.ts +33 -0
  9. package/dist/contract.d.ts.map +1 -0
  10. package/dist/graph.d.ts +67 -0
  11. package/dist/graph.d.ts.map +1 -0
  12. package/dist/index.d.ts +9 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +1988 -0
  15. package/dist/libsql.d.ts +57 -0
  16. package/dist/libsql.d.ts.map +1 -0
  17. package/dist/libsql.js +2662 -0
  18. package/dist/memory.d.ts +366 -0
  19. package/dist/memory.d.ts.map +1 -0
  20. package/dist/memory.js +3650 -0
  21. package/dist/ontology.d.ts +242 -0
  22. package/dist/ontology.d.ts.map +1 -0
  23. package/dist/operation.d.ts +24 -0
  24. package/dist/operation.d.ts.map +1 -0
  25. package/dist/projection-public.d.ts +59 -0
  26. package/dist/projection-public.d.ts.map +1 -0
  27. package/dist/projection-public.js +1682 -0
  28. package/dist/projection-suss.d.ts +17 -0
  29. package/dist/projection-suss.d.ts.map +1 -0
  30. package/dist/projection-suss.js +1721 -0
  31. package/dist/projection.d.ts +315 -0
  32. package/dist/projection.d.ts.map +1 -0
  33. package/dist/schema.d.ts +45 -0
  34. package/dist/schema.d.ts.map +1 -0
  35. package/dist/sdk.d.ts +51 -0
  36. package/dist/sdk.d.ts.map +1 -0
  37. package/dist/sdk.js +3072 -0
  38. package/dist/search.d.ts +34 -0
  39. package/dist/search.d.ts.map +1 -0
  40. package/dist/semantic.d.ts +83 -0
  41. package/dist/semantic.d.ts.map +1 -0
  42. package/dist/semantic.js +706 -0
  43. package/dist/sqlite/driver.d.ts +6 -0
  44. package/dist/sqlite/driver.d.ts.map +1 -0
  45. package/dist/sqlite/index.d.ts +5 -0
  46. package/dist/sqlite/index.d.ts.map +1 -0
  47. package/dist/sqlite/index.js +2840 -0
  48. package/dist/sqlite/migrations.d.ts +10 -0
  49. package/dist/sqlite/migrations.d.ts.map +1 -0
  50. package/dist/sqlite/port.d.ts +40 -0
  51. package/dist/sqlite/port.d.ts.map +1 -0
  52. package/dist/sqlite/runtime.d.ts +23 -0
  53. package/dist/sqlite/runtime.d.ts.map +1 -0
  54. package/dist/sqlite/store.d.ts +85 -0
  55. package/dist/sqlite/store.d.ts.map +1 -0
  56. package/dist/store.d.ts +236 -0
  57. package/dist/store.d.ts.map +1 -0
  58. package/dist/store.js +996 -0
  59. package/dist/sync.d.ts +57 -0
  60. package/dist/sync.d.ts.map +1 -0
  61. package/dist/sync.js +1328 -0
  62. package/package.json +121 -0
  63. package/skills/oh/SKILL.md +206 -0
  64. package/skills/oh/agents/openai.yaml +4 -0
  65. package/spec/README.md +74 -0
  66. package/spec/manifest.json +41 -0
  67. package/spec/v1/canonical-json.md +59 -0
  68. package/spec/v1/contract.json +28 -0
  69. package/spec/v1/contract.schema.json +58 -0
  70. package/spec/v1/embedding-profile.json +11 -0
  71. package/spec/v1/embedding.md +56 -0
  72. package/spec/v1/graph.md +87 -0
  73. package/spec/v1/memory.md +193 -0
  74. package/spec/v1/migration.md +92 -0
  75. package/spec/v1/ontology.json +55 -0
  76. package/spec/v1/ontology.md +80 -0
  77. package/spec/v1/operation.schema.json +138 -0
  78. package/spec/v1/projection-identity.schema.json +58 -0
  79. package/spec/v1/projection-query.schema.json +60 -0
  80. package/spec/v1/projection-result.schema.json +452 -0
  81. package/spec/v1/projection-rule-pack.schema.json +182 -0
  82. package/spec/v1/projection.md +165 -0
  83. package/spec/v1/record.schema.json +95 -0
  84. package/spec/v1/schema-evolution.md +51 -0
  85. package/spec/v1/schema-revision.schema.json +178 -0
  86. package/spec/v1/storage.md +88 -0
  87. package/spec/v1/store.md +131 -0
  88. package/spec/v1/sync-bundle.schema.json +51 -0
  89. package/spec/v1/sync.md +67 -0
  90. package/src/canonical.test.ts +46 -0
  91. package/src/canonical.ts +203 -0
  92. package/src/cli.test.ts +103 -0
  93. package/src/cli.ts +308 -0
  94. package/src/contract.ts +87 -0
  95. package/src/contracts.test.ts +147 -0
  96. package/src/graph.ts +248 -0
  97. package/src/index.ts +8 -0
  98. package/src/libsql.test.ts +657 -0
  99. package/src/libsql.ts +1687 -0
  100. package/src/memory.test.ts +783 -0
  101. package/src/memory.ts +1684 -0
  102. package/src/ontology.ts +573 -0
  103. package/src/operation.ts +80 -0
  104. package/src/projection-public.ts +53 -0
  105. package/src/projection-suss.ts +129 -0
  106. package/src/projection.test.ts +418 -0
  107. package/src/projection.ts +1457 -0
  108. package/src/schema.ts +156 -0
  109. package/src/sdk.ts +96 -0
  110. package/src/search.ts +66 -0
  111. package/src/semantic.test.ts +480 -0
  112. package/src/semantic.ts +333 -0
  113. package/src/sqlite/driver.ts +47 -0
  114. package/src/sqlite/index.ts +4 -0
  115. package/src/sqlite/migrations.test.ts +44 -0
  116. package/src/sqlite/migrations.ts +178 -0
  117. package/src/sqlite/port.test.ts +127 -0
  118. package/src/sqlite/port.ts +120 -0
  119. package/src/sqlite/runtime.test.ts +68 -0
  120. package/src/sqlite/runtime.ts +53 -0
  121. package/src/sqlite/store.test.ts +295 -0
  122. package/src/sqlite/store.ts +988 -0
  123. package/src/store.test.ts +121 -0
  124. package/src/store.ts +701 -0
  125. package/src/sync.test.ts +117 -0
  126. package/src/sync.ts +227 -0
package/package.json ADDED
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "@hraness/oh",
3
+ "version": "0.2.3",
4
+ "description": "open-source tools for agentic research",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Hraness",
8
+ "homepage": "https://oh.computer",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/hraness/oh.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/hraness/oh/issues"
15
+ },
16
+ "keywords": [
17
+ "agentic-research",
18
+ "knowledge-graph",
19
+ "ontology",
20
+ "sqlite"
21
+ ],
22
+ "private": false,
23
+ "sideEffects": false,
24
+ "packageManager": "bun@1.3.14",
25
+ "engines": {
26
+ "bun": ">=1.3.14",
27
+ "node": ">=24"
28
+ },
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "bin": {
32
+ "oh": "./dist/cli.js"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.js"
38
+ },
39
+ "./sdk": {
40
+ "types": "./dist/sdk.d.ts",
41
+ "import": "./dist/sdk.js"
42
+ },
43
+ "./store": {
44
+ "types": "./dist/store.d.ts",
45
+ "import": "./dist/store.js"
46
+ },
47
+ "./libsql": {
48
+ "types": "./dist/libsql.d.ts",
49
+ "import": "./dist/libsql.js"
50
+ },
51
+ "./sqlite": {
52
+ "types": "./dist/sqlite/index.d.ts",
53
+ "import": "./dist/sqlite/index.js"
54
+ },
55
+ "./sync": {
56
+ "types": "./dist/sync.d.ts",
57
+ "import": "./dist/sync.js"
58
+ },
59
+ "./semantic": {
60
+ "types": "./dist/semantic.d.ts",
61
+ "import": "./dist/semantic.js"
62
+ },
63
+ "./projection": {
64
+ "types": "./dist/projection-public.d.ts",
65
+ "import": "./dist/projection-public.js"
66
+ },
67
+ "./experimental/projection-suss": {
68
+ "types": "./dist/projection-suss.d.ts",
69
+ "import": "./dist/projection-suss.js"
70
+ },
71
+ "./experimental/memory": {
72
+ "types": "./dist/memory.d.ts",
73
+ "import": "./dist/memory.js"
74
+ },
75
+ "./package.json": "./package.json"
76
+ },
77
+ "files": [
78
+ "dist",
79
+ "src",
80
+ "spec",
81
+ "skills",
82
+ "README.md",
83
+ "LICENSE"
84
+ ],
85
+ "publishConfig": {
86
+ "access": "public"
87
+ },
88
+ "scripts": {
89
+ "build": "bun run build:js && bun run build:portable && bun run build:types",
90
+ "build:js": "bun build ./src/index.ts ./src/sdk.ts ./src/sqlite/index.ts ./src/sync.ts ./src/semantic.ts ./src/cli.ts --outdir ./dist --target bun --format esm --external bun:sqlite",
91
+ "build:portable": "bun build ./src/store.ts ./src/libsql.ts ./src/projection-public.ts ./src/projection-suss.ts ./src/memory.ts --outdir ./dist --target node --format esm --external @suss/datalog",
92
+ "build:types": "tsc -p tsconfig.build.json",
93
+ "check": "bun run typecheck && bun run test && bun run build && bun run test:types:node && bun run test:node && bun run test:node-projection",
94
+ "test:node": "node ./tests/node-portable.mjs",
95
+ "test:types:node": "tsc -p tsconfig.node-portable.json --noEmit",
96
+ "test": "bun test ./src ./tests ./site/tests/source.test.ts",
97
+ "test:node-projection": "node --test ./scripts/projection-node.test.mjs",
98
+ "typecheck": "tsc -p tsconfig.json --noEmit"
99
+ },
100
+ "devDependencies": {
101
+ "@suss/datalog": "0.20.0",
102
+ "@types/bun": "1.3.14",
103
+ "typescript": "5.9.3"
104
+ },
105
+ "peerDependencies": {
106
+ "@libsql/client": ">=0.17.4 <1",
107
+ "@suss/datalog": "0.20.0",
108
+ "@tobilu/qmd": "2.5.3"
109
+ },
110
+ "peerDependenciesMeta": {
111
+ "@libsql/client": {
112
+ "optional": true
113
+ },
114
+ "@suss/datalog": {
115
+ "optional": true
116
+ },
117
+ "@tobilu/qmd": {
118
+ "optional": true
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,206 @@
1
+ ---
2
+ name: oh
3
+ description: Operate a local hraness/oh ontology store through its checked CLI or SDK. Use when a coding agent needs to initialize, inspect, write, search, verify, export, import, or synchronize content-addressed research records in an Oh SQLite space.
4
+ ---
5
+
6
+ # Operate Oh
7
+
8
+ Keep the selected SQLite space authoritative. Inspect its contract and head
9
+ before writing, use generation-checked mutations, and verify replay after a
10
+ batch of changes.
11
+
12
+ ## Preserve authorization and location
13
+
14
+ - Resolve the repository instructions that apply to the target files first.
15
+ - Resolve the exact database path and space. Use `.oh/oh.sqlite` and `default`
16
+ only when they already exist or the user chose the defaults.
17
+ - Do not run a database command against a missing path merely to inspect it.
18
+ Oh opens and initializes the selected database as part of normal commands.
19
+ - Creating a database, tombstoning a record, importing a bundle, or syncing a
20
+ remote requires the user's request to include that write or its direct
21
+ workflow.
22
+ - Never put credentials, authentication tokens, or sensitive source text into
23
+ a record unless the user explicitly selected an appropriately protected
24
+ database and destination.
25
+
26
+ `oh --help` and `oh version` are side-effect-free installation checks:
27
+
28
+ ```sh
29
+ oh --help
30
+ oh version
31
+ ```
32
+
33
+ The supported CLI is `@hraness/oh@0.2.3` from the immutable `v0.2.3` GitHub
34
+ tag. It requires Bun 1.3.14 or newer. The versioned contract is published at
35
+ <https://oh.computer/spec/>.
36
+
37
+ ## Open an existing space
38
+
39
+ Confirm that the exact database is a regular file before a read command. First
40
+ inspect the installed runtime contract, then replay the database operation log:
41
+
42
+ ```sh
43
+ test -f .oh/oh.sqlite
44
+ oh contract
45
+ oh verify --db .oh/oh.sqlite --space default
46
+ ```
47
+
48
+ Stop if the installed contract differs from `oh.ontology.v1`, opening the
49
+ database reports a stored-contract mismatch, replay fails, or the user named
50
+ another database. Do not repair an integrity or contract failure by deleting
51
+ state.
52
+
53
+ Use the narrowest read:
54
+
55
+ ```sh
56
+ oh get entity:ada-lovelace --db .oh/oh.sqlite --space default
57
+ oh list --kind statement --limit 50 --db .oh/oh.sqlite --space default
58
+ oh log --limit 20 --db .oh/oh.sqlite --space default
59
+ oh search "analytical engine" --mode keyword --limit 10 \
60
+ --db .oh/oh.sqlite --space default
61
+ ```
62
+
63
+ A missing `get` exits with status 3 and prints no record. Treat it as absence,
64
+ not a corrupt database. CLI output is canonical JSON, so parse it rather than
65
+ scraping presentation text.
66
+
67
+ ## Initialize only when requested
68
+
69
+ Choose a confined path owned by the user's task. Do not overwrite or merge an
70
+ unrelated database.
71
+
72
+ ```sh
73
+ oh init --db .oh/oh.sqlite --space default
74
+ oh verify --db .oh/oh.sqlite --space default
75
+ ```
76
+
77
+ Record the returned head. Add the database directory to the repository's
78
+ ignore rules when it is local working state.
79
+
80
+ ## Write one checked record
81
+
82
+ Choose a stable lowercase logical key and one V1 kind. Current kinds include
83
+ `entity`, `statement`, `assertion`, `evidence`, `context`, `inquiry`, `schema`,
84
+ `vocabulary`, and the remaining kinds printed by `oh contract`.
85
+
86
+ 1. Read every declared dependency with `oh get`.
87
+ 2. Run `oh verify` and take `head.generation` from its JSON result.
88
+ 3. Prepare one valid JSON value. Prefer `--file` for structured or multiline
89
+ content and `--json` for a short literal.
90
+ 4. Use a stable operation ID when an exact retry must be idempotent.
91
+ 5. Pass the reviewed generation.
92
+
93
+ ```sh
94
+ oh put \
95
+ --kind statement \
96
+ --key statement:ada-program \
97
+ --depends-on entity:ada-lovelace \
98
+ --file /absolute/path/to/statement.json \
99
+ --actor agent.local \
100
+ --operation op_ada_program_v1 \
101
+ --expected-generation 4 \
102
+ --db .oh/oh.sqlite \
103
+ --space default
104
+ ```
105
+
106
+ If the expected generation is stale, read the new head and affected records,
107
+ reconcile the intended change, and create a new operation. Do not loop on a
108
+ conflict or change the expected generation without reviewing intervening work.
109
+
110
+ After a write batch, run:
111
+
112
+ ```sh
113
+ oh verify --db .oh/oh.sqlite --space default
114
+ ```
115
+
116
+ ## Tombstone deliberately
117
+
118
+ A tombstone removes the current record from the materialized graph while the
119
+ operation remains in history. Confirm the exact key and current digest. Check
120
+ that no retained record depends on it. Then require the reviewed generation:
121
+
122
+ ```sh
123
+ oh tombstone statement:obsolete \
124
+ --expected-generation 5 \
125
+ --operation op_remove_obsolete_v1 \
126
+ --db .oh/oh.sqlite \
127
+ --space default
128
+ ```
129
+
130
+ Run replay verification immediately. Do not edit SQLite tables directly to
131
+ bypass dependency or compare-and-swap checks.
132
+
133
+ ## Search with explicit evidence lanes
134
+
135
+ Use `keyword` for the model-free CLI path. `semantic` and `hybrid` need an SDK
136
+ instance configured with the optional local QMD backend. If a response contains
137
+ `semantic-unavailable`, report that diagnostic and preserve any keyword result;
138
+ do not substitute a hosted model.
139
+
140
+ Treat a search score as retrieval evidence, not proof that a research claim is
141
+ true. Open the returned record and its dependencies before relying on it.
142
+
143
+ ## Export or import an operation bundle
144
+
145
+ An export is read-only but writes a file when redirected. Choose the output
146
+ path explicitly and protect it like the source research:
147
+
148
+ ```sh
149
+ oh sync export --after 0 --limit 1000 \
150
+ --db .oh/oh.sqlite --space default > /absolute/path/to/oh-bundle.json
151
+ ```
152
+
153
+ Before import, preserve the destination, inspect its contract and head, and
154
+ confirm the bundle belongs to the same space. Import is sequential rather than
155
+ bundle-atomic: if a later operation conflicts, an earlier valid prefix may
156
+ already be present. After an error, inspect the destination head and run replay
157
+ verification before retrying.
158
+
159
+ ```sh
160
+ oh sync import --file /absolute/path/to/oh-bundle.json \
161
+ --db .oh/oh.sqlite --space default
162
+ oh verify --db .oh/oh.sqlite --space default
163
+ ```
164
+
165
+ Remote libSQL or Turso sync is an SDK workflow. The user must select the remote
166
+ and credential source. Never print credentials or embed them in records. Oh
167
+ settles fast-forward histories only; preserve both logs when it reports a
168
+ divergence.
169
+
170
+ ## Use composite memory only through host bindings
171
+
172
+ `@hraness/oh/experimental/memory` is an SDK-only surface. Do not let a model
173
+ construct its options. Trusted application code must bind two distinct
174
+ authority handles, exact binding digests, a pinned canonical head, working
175
+ codecs, a working actor, domain extractor relation ownership and digests,
176
+ host-purposed named rule/query programs, and named nomination routes before
177
+ giving the returned object to an agent.
178
+
179
+ The agent-facing object may call only `remember`, `query`, `explain`, and
180
+ `nominate`. Never add a tool parameter for a database path or URL, authority,
181
+ realm, space, store profile, rule pack, raw query, sync destination, canonical
182
+ write, caller-asserted actor/time, or purge operation. Preserve lane, conflict,
183
+ fact-policy, and premise-authority labels in query output. Treat every result
184
+ as derived. A nomination may select only a host-registered route and is a
185
+ prepared dependency-closure candidate for destination-owned review, not
186
+ permission to write durable knowledge or import the working operation chain.
187
+
188
+ Use `createOhMemoryAgentV2` only when the host has registered primitive
189
+ query-body parameters and fixed all projection, row, page, and page-byte
190
+ limits. Expose only the exact bindings object, program ID, and continuation to
191
+ the model. Do not expose parameter declarations, page size, or evaluator
192
+ options as tool input. Follow `hasMore` until the continuation is `null`, and
193
+ restart the named query after an integrity error; never combine pages across a
194
+ working-head change. A V2 `query-limit` or `result-bytes` condition is a failed
195
+ query, not a partial answer. Treat each continuation as a bearer cursor: pass
196
+ it back unchanged only to the exact query and do not log or edit it. If the
197
+ host reconstructs the facade or routes across replicas, it must provide the
198
+ same private 32 through 64 byte `continuationKey` in host options; never expose
199
+ that key as tool input. Keep row-level `proofsTruncated` evidence visible.
200
+
201
+ ## Finish with evidence
202
+
203
+ Report the exact database and space, reads or mutations performed, final head
204
+ generation and operation digest, replay result, search diagnostics, and any
205
+ sync counts. Do not claim success from a command exit alone when `oh verify`
206
+ was part of the requested workflow.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Oh"
3
+ short_description: "Operate local agentic research records"
4
+ default_prompt: "Use $oh to inspect and safely update my local research space."
package/spec/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Oh specification
2
+
3
+ This directory is the versioned public contract for Oh. It defines the
4
+ canonical bytes, ontology identities, graph envelopes, schema revisions,
5
+ SQLite and direct libSQL authority, operation sync, store profiles, and local
6
+ embedding profile that independent implementations need to interoperate.
7
+
8
+ [`manifest.json`](manifest.json) is the discovery document. V1 is current and
9
+ binds these versions:
10
+
11
+ | Component | Version |
12
+ | --- | --- |
13
+ | Ontology | `1.0.0` |
14
+ | Contract ID | `oh.ontology.v1` |
15
+ | Graph format | `1` |
16
+ | Schema format | `1` |
17
+ | SQLite schema | `2` |
18
+ | Sync protocol | `oh.sync.v1` |
19
+ | Embedding profile | `1` |
20
+ | Projection semantics | `oh.projection.positive-datalog.v1` |
21
+ | Composite memory | `experimental v1` |
22
+
23
+ ## V1 documents
24
+
25
+ - [Canonical JSON and digests](v1/canonical-json.md)
26
+ - [Ontology](v1/ontology.md)
27
+ - [Schema evolution](v1/schema-evolution.md)
28
+ - [Graph and operations](v1/graph.md)
29
+ - [SQLite storage](v1/storage.md)
30
+ - [Store ports, profiles, and direct libSQL authority](v1/store.md)
31
+ - [Sync protocol](v1/sync.md)
32
+ - [Local embedding profile](v1/embedding.md)
33
+ - [Derived projections](v1/projection.md)
34
+ - [Experimental composite agent memory](v1/memory.md)
35
+ - [Compatibility and migration](v1/migration.md)
36
+
37
+ Machine-readable V1 artifacts:
38
+
39
+ - [`contract.json`](v1/contract.json)
40
+ - [`ontology.json`](v1/ontology.json)
41
+ - [`embedding-profile.json`](v1/embedding-profile.json)
42
+ - [`contract.schema.json`](v1/contract.schema.json)
43
+ - [`record.schema.json`](v1/record.schema.json)
44
+ - [`schema-revision.schema.json`](v1/schema-revision.schema.json)
45
+ - [`operation.schema.json`](v1/operation.schema.json)
46
+ - [`sync-bundle.schema.json`](v1/sync-bundle.schema.json)
47
+ - [`projection-rule-pack.schema.json`](v1/projection-rule-pack.schema.json)
48
+ - [`projection-query.schema.json`](v1/projection-query.schema.json)
49
+ - [`projection-identity.schema.json`](v1/projection-identity.schema.json)
50
+ - [`projection-result.schema.json`](v1/projection-result.schema.json)
51
+
52
+ ## Conformance
53
+
54
+ The words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY state interoperability
55
+ requirements. JSON Schemas validate exchange structure. The narrative
56
+ documents and runtime parsers also define canonical order, digest preimages,
57
+ byte limits, dependency laws, and replay behavior that JSON Schema cannot
58
+ express.
59
+
60
+ An implementation conforms to V1 only when it reproduces exact canonical JSON
61
+ and digests, rejects malformed or noncanonical input, preserves ordered
62
+ operation history, and passes the same replay laws. Accepting more input is not
63
+ conformance when the extra input changes persisted or exchanged bytes.
64
+
65
+ ## Versioning
66
+
67
+ An existing version is immutable. A change to serialized keys, accepted value
68
+ grammar, ordering, a digest preimage, a record kind, a limit, migration SQL, or
69
+ protocol meaning needs a new version. New convenience APIs may retain the
70
+ current contract when they produce the same checked bytes.
71
+
72
+ Schema records inside an Oh graph have their own namespace, code, revision, and
73
+ content digest. Their evolution rules are separate from the version of the Oh
74
+ envelope itself.
@@ -0,0 +1,41 @@
1
+ {
2
+ "current": "v1",
3
+ "homepage": "https://oh.computer",
4
+ "package": "@hraness/oh",
5
+ "repository": "https://github.com/hraness/oh",
6
+ "v": 1,
7
+ "versions": [
8
+ {
9
+ "contract": "./v1/contract.json",
10
+ "contractId": "oh.ontology.v1",
11
+ "contractSha256": "e53ae573c2af417082be9f554d0f6f3e317f054daf745181f462608e3f622594",
12
+ "embeddingProfile": "./v1/embedding-profile.json",
13
+ "id": "v1",
14
+ "memory": {
15
+ "specification": "./v1/memory.md"
16
+ },
17
+ "ontology": "./v1/ontology.json",
18
+ "projection": {
19
+ "identitySchema": "./v1/projection-identity.schema.json",
20
+ "querySchema": "./v1/projection-query.schema.json",
21
+ "resultSchema": "./v1/projection-result.schema.json",
22
+ "rulePackSchema": "./v1/projection-rule-pack.schema.json",
23
+ "specification": "./v1/projection.md"
24
+ },
25
+ "schemas": [
26
+ "./v1/contract.schema.json",
27
+ "./v1/record.schema.json",
28
+ "./v1/schema-revision.schema.json",
29
+ "./v1/operation.schema.json",
30
+ "./v1/sync-bundle.schema.json",
31
+ "./v1/projection-rule-pack.schema.json",
32
+ "./v1/projection-query.schema.json",
33
+ "./v1/projection-identity.schema.json",
34
+ "./v1/projection-result.schema.json"
35
+ ],
36
+ "specification": "./v1/ontology.md",
37
+ "status": "current",
38
+ "v": 1
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,59 @@
1
+ # Canonical JSON and digests V1
2
+
3
+ Every content digest in Oh is SHA-256 over UTF-8 canonical JSON. The lowercase
4
+ 64-character hexadecimal digest is part of the record, operation, schema,
5
+ vocabulary, contract, or sync envelope that names it.
6
+
7
+ ## Accepted JSON
8
+
9
+ V1 accepts JSON null, booleans, strings, finite numbers other than negative
10
+ zero, arrays, and plain objects. It rejects non-finite numbers, `-0`, unpaired
11
+ UTF-16 surrogates, cycles, non-plain objects, `undefined`, bigint, symbols, and
12
+ functions.
13
+
14
+ Canonical encoding has these rules:
15
+
16
+ 1. Sort object keys by JavaScript's default UTF-16 code-unit order.
17
+ 2. Preserve array order exactly.
18
+ 3. Encode strings and finite numbers with the ECMAScript JSON representation.
19
+ 4. Emit no insignificant whitespace.
20
+ 5. Preserve a valid string's code points. General canonical JSON does not
21
+ normalize text. Ontology text fields separately require NFC where stated.
22
+
23
+ The result is RFC 8785-style canonical JSON for the narrower JSON subset
24
+ accepted by Oh. Implementations MUST reproduce Oh's exact V1 ordering and
25
+ number rules instead of substituting a serializer whose edge cases differ.
26
+
27
+ ## Parsing canonical bytes
28
+
29
+ A canonical JSON parser MUST bound input before parsing, parse JSON, encode the
30
+ value again with the V1 rules, and require byte-for-byte equality with the
31
+ input. Pretty-printed or differently ordered JSON can be accepted as user
32
+ input only when the receiving command explicitly canonicalizes it before the
33
+ value reaches a persisted or exchanged boundary.
34
+
35
+ ## Digest preimages
36
+
37
+ Each creator hashes the envelope without its own digest field:
38
+
39
+ - `recordSha256` hashes `dependencies`, `key`, `kind`, `v`, and `value`.
40
+ - `schemaSha256` hashes the schema revision without `schemaSha256`.
41
+ - `vocabularySha256` hashes the vocabulary revision without
42
+ `vocabularySha256`.
43
+ - `recordsSha256` hashes the ordered complete record-reference array. Each
44
+ reference contains `dependencies`, `key`, `kind`, `sha256`, and `v`.
45
+ - `graphRevisionSha256` hashes `changes`, `operationId`,
46
+ `parentGraphRevisionSha256`, `recordsSha256`, `revision`, and `v`.
47
+ - `operationSha256` hashes the operation without `operationSha256`.
48
+ - `bundleSha256` hashes the sync bundle without `bundleSha256`.
49
+ - `contractSha256` hashes the contract manifest without `contractSha256`.
50
+
51
+ Parsers MUST recompute and compare the digest. They MUST NOT trust a digest
52
+ because its syntax is valid.
53
+
54
+ ## Bounds
55
+
56
+ V1 bounds a graph record value at 1,048,576 canonical UTF-8 bytes and an
57
+ operation at 67,108,864 bytes. The general canonical text parser defaults to
58
+ 16 MiB. More specific ontology fields may have smaller limits. A receiver MUST
59
+ apply the smallest applicable bound before unbounded allocation or work.
@@ -0,0 +1,28 @@
1
+ {
2
+ "contractId": "oh.ontology.v1",
3
+ "contractSha256": "e53ae573c2af417082be9f554d0f6f3e317f054daf745181f462608e3f622594",
4
+ "graphFormatVersion": 1,
5
+ "ontologyVersion": "1.0.0",
6
+ "recordKinds": [
7
+ "activity",
8
+ "assertion",
9
+ "context",
10
+ "dependency-manifest",
11
+ "edition",
12
+ "entity",
13
+ "evidence",
14
+ "identity-operation",
15
+ "inquiry",
16
+ "inquiry-event",
17
+ "review-decision",
18
+ "rights-decision",
19
+ "schema",
20
+ "shape",
21
+ "statement",
22
+ "type-membership",
23
+ "view",
24
+ "vocabulary"
25
+ ],
26
+ "schemaFormatVersion": 1,
27
+ "v": 1
28
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$id": "https://oh.computer/spec/v1/contract.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "contractId": {
7
+ "const": "oh.ontology.v1"
8
+ },
9
+ "contractSha256": {
10
+ "const": "e53ae573c2af417082be9f554d0f6f3e317f054daf745181f462608e3f622594"
11
+ },
12
+ "graphFormatVersion": {
13
+ "const": 1
14
+ },
15
+ "ontologyVersion": {
16
+ "const": "1.0.0"
17
+ },
18
+ "recordKinds": {
19
+ "const": [
20
+ "activity",
21
+ "assertion",
22
+ "context",
23
+ "dependency-manifest",
24
+ "edition",
25
+ "entity",
26
+ "evidence",
27
+ "identity-operation",
28
+ "inquiry",
29
+ "inquiry-event",
30
+ "review-decision",
31
+ "rights-decision",
32
+ "schema",
33
+ "shape",
34
+ "statement",
35
+ "type-membership",
36
+ "view",
37
+ "vocabulary"
38
+ ]
39
+ },
40
+ "schemaFormatVersion": {
41
+ "const": 1
42
+ },
43
+ "v": {
44
+ "const": 1
45
+ }
46
+ },
47
+ "required": [
48
+ "contractId",
49
+ "contractSha256",
50
+ "graphFormatVersion",
51
+ "ontologyVersion",
52
+ "recordKinds",
53
+ "schemaFormatVersion",
54
+ "v"
55
+ ],
56
+ "title": "Oh contract manifest V1",
57
+ "type": "object"
58
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "dimensions": 768,
3
+ "distance": "cosine",
4
+ "documentFormat": "title: {title} | text: {content}",
5
+ "documentation": "https://ai.google.dev/gemma/docs/embeddinggemma",
6
+ "engine": "@tobilu/qmd@2.5.3",
7
+ "model": "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf",
8
+ "normalization": "l2",
9
+ "queryFormat": "task: search result | query: {query}",
10
+ "v": 1
11
+ }
@@ -0,0 +1,56 @@
1
+ # Local embedding profile V1
2
+
3
+ Oh semantic search is optional, local, and derived. SQLite records remain
4
+ authoritative. Keyword search remains available without a model.
5
+
6
+ ## Exact profile
7
+
8
+ | Field | Value |
9
+ | --- | --- |
10
+ | Engine | `@tobilu/qmd@2.5.3` |
11
+ | Model | `hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf` |
12
+ | Dimensions | `768` |
13
+ | Distance | `cosine` |
14
+ | Normalization | `l2` |
15
+ | Documentation | `https://ai.google.dev/gemma/docs/embeddinggemma` |
16
+ | Query format | `task: search result | query: {query}` |
17
+ | Document format | `title: {title} \| text: {content}` |
18
+ | Profile version | `1` |
19
+
20
+ The native 768-dimensional output follows the
21
+ [EmbeddingGemma model profile](https://ai.google.dev/gemma/docs/embeddinggemma).
22
+ Implementations MUST NOT silently truncate it to another Matryoshka dimension
23
+ under profile V1.
24
+
25
+ ## Derived document contract
26
+
27
+ For each current record, Oh writes one local Markdown document whose filename
28
+ is the SHA-256 digest of the logical key. The document includes the key, kind,
29
+ and canonical JSON value. A canonical manifest binds that filename to the
30
+ logical key and exact `recordSha256`.
31
+
32
+ Before returning a semantic hit, Oh resolves the filename through the manifest,
33
+ loads the current SQLite record, and requires its digest to match. Stale,
34
+ unknown, duplicate, non-finite, or out-of-range results are discarded.
35
+
36
+ ## Search modes
37
+
38
+ - `keyword` uses the local FTS5 index only.
39
+ - `semantic` uses the configured local backend only.
40
+ - `hybrid` combines keyword and semantic ranks while preserving lane, rank,
41
+ and score as evidence.
42
+
43
+ When no semantic backend is configured, semantic and hybrid requests return a
44
+ `semantic-unavailable` diagnostic rather than contacting a hosted provider.
45
+ Hybrid can still return its keyword lane.
46
+
47
+ ## Deployment boundary
48
+
49
+ The base package MUST remain usable without QMD. A serverless or browser bundle
50
+ SHOULD exclude QMD and model artifacts. Cloud applications SHOULD keep exact
51
+ and keyword retrieval on the request path and run semantic indexing in a
52
+ bounded, long-lived local-model worker. Unavailable semantic search should be
53
+ visible as a diagnostic, never replaced silently by a different model.
54
+
55
+ The cache directory can contain derived record text. It needs the same local
56
+ confidentiality treatment as the source data even though it can be rebuilt.