create-githolon 0.98.3 → 0.100.0

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.
package/index.mjs CHANGED
@@ -17,7 +17,7 @@ var NOMOS_VERSION = (() => {
17
17
  var args = process.argv.slice(2);
18
18
  if (args.includes("-h") || args.includes("--help")) {
19
19
  process.stdout.write(
20
- "create-githolon \u2014 scaffold a Nomos domain package\n\nUsage:\n npm create githolon <dir> (or: npx create-githolon <dir>)\n\nScaffolds the starter domain + compile config + live e2e into <dir>\n(default: my-holon-app) and inits a git repo. After `githolon compile`,\n`githolon ledger init holon` mints YOUR holon locally \u2014 verified by the\nsame wasm gate the cloud runs, ready to birth by git push.\n\nFlags:\n --no-git skip git init\n"
20
+ "create-githolon \u2014 scaffold a Nomos business-law package\n\nUsage:\n npm create githolon <dir> (or: npx create-githolon <dir>)\n\nScaffolds one aggregate, one business birth, the compile config, and a\none-page explanation into <dir> (default: my-holon-app). The generated\nproof exercises the real local engine.\n\nFlags:\n --no-git skip git init\n"
21
21
  );
22
22
  process.exit(0);
23
23
  }
@@ -41,7 +41,7 @@ if (existsSync(path.join(targetDir, "vscode"))) {
41
41
  }
42
42
  var appHash = `${appName.replace(/[-\s]+/g, "_").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase()}_DOMAIN_HASH`;
43
43
  var subst = (s) => s.replaceAll("__APP_NAME__", appName).replaceAll("__APP_HASH__", appHash).replaceAll("__NOMOS_VERSION__", NOMOS_VERSION);
44
- for (const f of ["package.json", "README.md", "nomos.package.mjs", "CLAUDE.md", "domains/todo.ts", "test/e2e.mts"]) {
44
+ for (const f of ["package.json", "README.md", "nomos.package.mjs", "CLAUDE.md", "domains/todo.ts"]) {
45
45
  const p = path.join(targetDir, f);
46
46
  if (existsSync(p)) writeFileSync(p, subst(readFileSync(p, "utf8")), "utf8");
47
47
  }
@@ -59,19 +59,15 @@ process.stdout.write(
59
59
  `
60
60
  Scaffolded ${appName} into ${rel}/${gitInited ? " (git repo)" : ""}
61
61
 
62
- Read docs/01-mental-model.md first \u2014 the docs travel with you, offline.
62
+ Nomos in one page: ${path.join(rel, "README.md")}
63
63
 
64
64
  Next:
65
65
  cd ${rel}
66
66
  npm install
67
- npx githolon compile # \u2192 build/: deployable package + manifests + typed client + a generated proof
68
- npx githolon proof # run that proof live \u2014 GENERATED from your own law, no test rewriting
69
- npx githolon login --agent # a verified identity, no browser
67
+ npx githolon compile # law + typed client + generated proof
68
+ npx githolon proof # births your model in the real local engine
70
69
 
71
- Your law compiles + proves OFFLINE today (compile + proof above \u2014 no cloud, no account).
72
- To run it LIVE, deploy to a workspace you own: a workspace is born by its PARENT (a platform
73
- you control births homes/children \u2014 birthHome/birthChild). There is no host-side create \u2014 the
74
- flat 'ws create' lane is retired (orphanless holarchy). See docs/04-cloud.md for the birth-on-
75
- parent flow; self-serve keyless birth-under-root is in flight.
70
+ The starter exposes one creation idea: app.birth(businessFacts).
71
+ Identity, authorship, persistence, synchronisation, provenance, and recovery stay underneath it.
76
72
  `
77
73
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-githolon",
3
- "version": "0.98.3",
3
+ "version": "0.100.0",
4
4
  "type": "module",
5
5
  "description": "Scaffold a Nomos domain package: the starter domain + compile config + live e2e. `npm create githolon my-app`.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -1,36 +1,13 @@
1
- # __APP_NAME__ — Nomos domain package
1
+ # __APP_NAME__
2
2
 
3
- A local-first Nomos domain: law authored in the `@githolon/dsl` TypeScript DSL under
4
- `domains/`, compiled into ONE deterministic GitHolon artifact, deployed to a workspace.
5
- Read `docs/01-mental-model.md` first — the docs travel with this repo, offline.
6
-
7
- ## For AI agents
8
-
9
- This project's law is guarded by an author-time gate (static twins). Use it:
10
-
11
- - **Lint the law** — before compiling or deploying, run the gate over `nomos.package.mjs`:
12
-
13
- ```bash
14
- npx githolon check # human report; exits non-zero on any REFUSE
15
- npx githolon check --json # the findings as a machine-readable array (file:line)
16
- ```
17
-
18
- - **Preview a law evolution** — before deploying a change to already-deployed law, diff
19
- against the prior deployed law and paste any generated `dispositions` block:
20
-
21
- ```bash
22
- npx githolon check --against build/<name>.deploy.json
23
- ```
24
-
25
- - **Editor / agent diagnostics** — `npx githolon lsp` is a standard stdio Language Server
26
- (red squiggles as you write law). For Claude Code, the `nomos-law` plugin ships it as a
27
- plugin LSP; for Codex or other MCP clients, `githolon mcp` exposes the same gate as the
28
- `nomos_check` and `nomos_evolve_preview` tools (`codex mcp add nomos -- githolon mcp`).
29
-
30
- ## The loop
3
+ This is a Nomos business-law package. Keep application code at the level of aggregates, `birth`, directives, and reads.
31
4
 
32
5
  ```bash
33
- npx githolon compile # → build/: deployable package + typed client + a generated proof
34
- npx githolon proof # run that proof offline on a local holon
35
- npx githolon deploy <ws>
6
+ npx githolon check
7
+ npx githolon compile
8
+ npx githolon proof
36
9
  ```
10
+
11
+ `check` reports statically provable refusals. `compile` emits the law and typed client. `proof` exercises the generated business path in the real local engine.
12
+
13
+ Do not introduce application-facing identity, signing, storage, deployment, or recovery ceremonies. They belong beneath the generated `birth(payload)` surface.
@@ -1,144 +1,63 @@
1
- # __APP_NAME__ — a Nomos domain package
2
-
3
- Scaffolded by `npm create githolon`. One domain file, one config, one command —
4
- then an offline-first typed client against Nomos Cloud. Two ways to get a live
5
- workspace; both end in the same place.
1
+ # __APP_NAME__
2
+
3
+ Nomos lets you describe a business and leave the compute science to the framework.
4
+
5
+ You write three things:
6
+
7
+ - aggregates: the business things that exist;
8
+ - birth: the facts required to give one of those things a durable life;
9
+ - directives and reads: what may happen to it and what the application may ask.
10
+
11
+ The starter in [`domains/todo.ts`](domains/todo.ts) gives a todo list its own durable life:
12
+
13
+ ```ts
14
+ export const TodoList = aggregate("TodoList", {
15
+ reference: t.string().merge(Lww),
16
+ title: t.string().merge(Lww),
17
+ });
18
+
19
+ export const todoList = birth(TodoList, {
20
+ payload: z.object({
21
+ reference: z.string().min(1),
22
+ title: z.string().min(1),
23
+ }),
24
+ key: (facts) => facts.reference,
25
+ plan: (list, facts) => list
26
+ .set("reference", facts.reference)
27
+ .set("title", facts.title),
28
+ });
29
+ ```
6
30
 
7
- New here? Read [docs/01-mental-model.md](./docs/01-mental-model.md) first — the
8
- docs travel with you, offline (the full index is [below](#docs--in-the-box)).
31
+ The generated client exposes the same business idea:
9
32
 
10
- ```bash
11
- npm install
12
- npx githolon compile # → build/: deployable package + manifests + typed client + a generated proof
13
- npx githolon proof # run that proof live — GENERATED from your own law, no test rewriting
14
- npx githolon login --agent # self-onboard a verified identity (no browser; linkable to a full account later)
33
+ ```ts
34
+ const list = await app.birth({
35
+ reference: "PERSONAL",
36
+ title: "Things to do",
37
+ });
15
38
  ```
16
39
 
17
- **The shortest complete proof** — `npm install && npx githolon compile && npm run e2e`
18
- — IS the whole demonstration: your law deploys to a throwaway workspace, an
19
- ENFORCED-offline write (fetch is trapped) syncs through edge admission, and the
20
- cloud answers your declared query and count. Paths A/B below are for keeping a
21
- real workspace afterwards.
40
+ That is the model. A born aggregate is a holon: its law, facts, and history travel together. It can act locally, survive disconnection, converge with other copies, explain every accepted change, and be reconstructed from its history.
41
+
42
+ Nomos owns everything underneath `birth`: durable identity, authorship, law installation, local execution, validation, persistence, synchronisation, provenance, and recovery. Those mechanisms are implementation details, not application design choices.
22
43
 
23
- ## Path A — deploy your law
44
+ The development loop is one path:
24
45
 
25
46
  ```bash
26
- npx githolon ws create <ws> # births a fresh workspace on your identity; SAVES its one-time secret to ~/.holon
27
- npx githolon deploy <ws> # POSTs build/__APP_NAME__.deploy.json with the stored secret
28
- npm run e2e # the full loop, live: offline write → sync → admission → cloud query
47
+ npm install
48
+ npx githolon compile
49
+ npx githolon proof
29
50
  ```
30
51
 
31
- ## Path B — mint a holon LOCALLY, push it, the cloud agrees
52
+ `compile` emits the law, typed client, and a proof generated from this domain. `proof` drives the real engine locally, births the list, discards its resident copy, restores it from durable custody, verifies the full history again, and reads the business root back.
32
53
 
33
- This is the point of holons: predefined law you can assert to be true on your
34
- own machine, then have independently validated in the cloud. `ledger init`
35
- builds a brand-new GitHolon ledger locally — genesis (the nomos controller),
36
- then YOUR compiled law, every intent stamped `installedBy: <your identity>` —
37
- and verifies the chain with the SAME byte-identical wasm gate the cloud runs.
38
- Pushing it to an unborn workspace makes the cloud replay-verify the whole chain
39
- from genesis and re-derive your exact verdict (same head, same plans re-run)
40
- before serving anything. Authority lives in the git; no holon outranks another.
54
+ Make it yours by renaming `TodoList`, changing its fields, and changing the birth payload. Keep the rule: application code supplies business facts; Nomos owns the machinery that makes those facts durable and trustworthy.
41
55
 
42
- ```bash
43
- npx githolon ledger init holon # mint + assert locally: chain VALID, head <h>, under YOUR uid
44
- npx githolon ledger verify holon # re-assert any time
45
- cd holon
46
- npx githolon ws create <ws> # birth the workspace (its parent's offer-effect); no secret minted
47
- npx githolon git remote <ws> # wire the remote + credential helper for syncing
48
- git push nomos refs/heads/session/<id> # sync your writes to the edge (main is not push-writable)
49
- npx githolon deploy <ws> # idempotent (alreadyInstalled) + stages the read manifests so queries route
50
- cd ..
51
- ```
56
+ Useful files:
57
+
58
+ - [`domains/todo.ts`](domains/todo.ts): the business model;
59
+ - [`nomos.package.mjs`](nomos.package.mjs): the modules compiled into the package;
60
+ - `build/__APP_NAME__.client.ts`: the generated typed client after `compile`;
61
+ - `build/__APP_NAME__.proof.mts`: the generated proof after `compile`.
52
62
 
53
- After birth, `holon/` tracks YOUR workspace: new writes admitted on main arrive
54
- with `git pull`. (`githolon git setup` installed a git credential helper, so plain
55
- git just works against the cloud.)
56
-
57
- ## Make it YOURS — the five-minute walkthrough
58
-
59
- The starter is the tutorial; this is the exact path from the todo list to your own law.
60
-
61
- 1. **Rename the law file** and reshape it:
62
- `git mv domains/todo.ts domains/<yours>.ts` — keep the patterns
63
- (aggregate fields each tagged a merge driver — `Lww` scalar, `AddWins` set;
64
- directives = zod payload → pure plan; `addToSet` for AddWins sets — `set()` on
65
- a set field is refused; `done` is a 2-value Lww enum because there is no
66
- `t.bool()`; sharing is one native Zanzibar tuple via `writeTuple`).
67
- 2. **Point the compile config at it** — `nomos.package.mjs`:
68
- ```js
69
- export default { name: "<pkg>", domains: [{ key: "<pkg>", modules: ["./domains/<yours>.ts"] }] };
70
- ```
71
- **Naming convention: there isn't one.** `<pkg>` can be whatever you'd actually
72
- call it — `potluck`, `tool-library`, `study_group`, even `Tool Library`.
73
- Artifact filenames keep your name verbatim (`build/<pkg>.client.ts`); the
74
- generated symbols normalize it for you (`toolLibraryClient(holon)`,
75
- `TOOL_LIBRARY_DOMAIN_HASH`).
76
- 3. **Compile and read what you built:**
77
- ```bash
78
- npx githolon compile && cat build/<pkg>.summary.txt
79
- ```
80
- 4. **Re-point the proof** — `build/<pkg>.proof.mts` needs nothing: it is
81
- REGENERATED from your law on every compile (`npx githolon proof` runs it).
82
- The narrated `test/e2e.mts` is yours to reshape: update the client import and
83
- the directive/query/count names; `npm run typecheck` names every stale
84
- reference until it's clean.
85
- 5. **Prove it live:** `npm run e2e` — your law deploys to a throwaway workspace,
86
- an offline write syncs through admission, the cloud answers your declared
87
- query and count, and one native sharing tuple is recorded. (Prove it OFFLINE
88
- first with `npx githolon proof` — the generated proof on a local holon, no
89
- cloud.)
90
-
91
- Then deploy it for real: `npx githolon login --agent && npx githolon ws create <ws> && npx githolon deploy <ws>`.
92
-
93
- ## Docs — in the box
94
-
95
- `docs/` travels with you — offline, like everything else here. Seven short
96
- pages, each under a screen and a half:
97
-
98
- 1. [The mental model](./docs/01-mental-model.md) — holons, content-addressed
99
- law, custody-not-truth, admission, no server authority.
100
- 2. [Authoring law](./docs/02-authoring.md) — aggregates, field kinds, the
101
- merge-driver table, plan ops (`addToSet` vs `set`), determinism rules,
102
- declared reads (query/count/derived/sum).
103
- 3. [The client](./docs/03-client.md) — `connect`, the generated client
104
- contract, `sync` semantics (`admission: null` is normal), watches, dead
105
- letters, the two-clientId concurrency proof.
106
- 4. [Nomos Cloud](./docs/04-cloud.md) — both deploy lanes, `login --agent`
107
- identity, retirement + data retention per the license, DLQ retry, quotas.
108
- 5. [Superpowers](./docs/05-superpowers.md) — mint a holon locally, the upload
109
- birth, byte-identical wasm everywhere, the enforced-offline proof.
110
- 6. [Evolving law](./docs/06-law-evolution.md) — what's safe to change once
111
- real data exists (add freely; rename/retype honestly), the era rule, and
112
- the one trap: old clients after a breaking upgrade.
113
- 7. [Security](./docs/07-security.md) — private aggregates (`requires(cap)` +
114
- grant/revoke, the holon gates its own reads) and operator-blind E2E
115
- encrypted fields (`.encrypted()`, the key handshake, `githolon decrypt`).
116
-
117
- ## What's here
118
-
119
- - `docs/` — the seven pages above; the offline reference.
120
- - `domains/todo.ts` — the starter domain (the law): a shared, offline-first todo
121
- list — two aggregates, the directives, a declared query, a where-filtered count,
122
- and one native Zanzibar sharing tuple. Rename it, reshape it, or add domains
123
- with `npx githolon generate domain <name>`.
124
- - `nomos.package.mjs` — the compile config (module list per domain key; reads
125
- are auto-discovered from exports).
126
- - `build/__APP_NAME__.client.ts` — GENERATED typed TS client (payload types from
127
- the engine's zod, read models from the field kinds, the law hash baked in).
128
- - `build/__APP_NAME__.proof.mts` — GENERATED runnable proof, synthesized from your
129
- own directives/queries/counts on every compile; `npx githolon proof` runs it.
130
- - `test/e2e.mts` — proves compile → deploy → typed offline write/query →
131
- edge admission → cloud declared query, against the live cloud.
132
- - `holon/` (after `ledger init`) — YOUR ledger, a normal git repo. Inspect it:
133
- every commit is an intent envelope; `git log` IS the audit trail.
134
-
135
- ## Authoring rules (the engine enforces these)
136
-
137
- - A directive's plan is a PURE function of `(payload, ports)` — timestamps ride
138
- in the payload as ISO strings; no `Date.now()` / `Math.random()`. You rarely
139
- stamp one by hand: payload fields named `…At` are auto-filled with ISO now()
140
- by the generated client when you omit them (an explicit value always wins).
141
- - `create(Agg)` mints ids — `.creates` payloads never carry one.
142
- - Merge drivers are the law: `Lww`, `AddWins`, `MapOf(Lww)`.
143
-
144
- Everything you write here, and everything the tools generate for you, is yours.
63
+ If you need to understand distributed systems, cryptography, storage topology, or recovery ceremonies to model the business, that concern has leaked out of Nomos.
@@ -1,77 +1,25 @@
1
1
  /**
2
- * __APP_NAME__ — a shared, offline-first todo list. The smallest domain that shows the
3
- * magic: two people edit the SAME list while BOTH offline, blind to each other, and
4
- * converge byte-identically when they sync — because the merge is the LAW (kernel-folded
5
- * CRDT), not the app's job. You write only aggregates + directives; the engine does the
6
- * rest. Rename it, add fields, add directives — it's yours from the first byte.
2
+ * __APP_NAME__ — the complete starter model.
3
+ *
4
+ * The app supplies business facts. Nomos gives the aggregate a durable life and owns identity,
5
+ * authorship, local execution, synchronisation, persistence, provenance, and recovery beneath it.
7
6
  */
8
- import {
9
- z, aggregate, t, Lww, AddWins, directive, create, instance, set, addToSet,
10
- query, count, writeTuple, RelationTuple, relationTuplesByObject,
11
- } from "@githolon/dsl";
7
+ import { Lww, aggregate, birth, t, z } from "@githolon/dsl";
12
8
 
13
- // ── what we store ─────────────────────────────────────────────────────────────
14
9
  export const TodoList = aggregate("TodoList", {
15
- title: t.string().merge(Lww), // last writer wins
10
+ /** A stable business key the caller already knows. */
11
+ reference: t.string().merge(Lww),
12
+ title: t.string().merge(Lww),
16
13
  });
17
14
 
18
- export const Todo = aggregate("Todo", {
19
- listId: t.string().merge(Lww), // which list this todo is on (the query key)
20
- text: t.string().merge(Lww), // last writer wins
21
- done: t.bool(), // a flag — Lww by default; reads back a real boolean
22
- tags: t.set(t.string()).merge(AddWins), // concurrent taggers UNION — nobody's tag is lost
15
+ /** The one public creation idea: give a todo list its own durable life. */
16
+ export const todoList = birth(TodoList, {
17
+ payload: z.object({
18
+ reference: z.string().min(1),
19
+ title: z.string().min(1),
20
+ }),
21
+ key: (facts) => facts.reference,
22
+ plan: (list, facts) => list
23
+ .set("reference", facts.reference)
24
+ .set("title", facts.title),
23
25
  });
24
-
25
- // ── what people do (directives PLAN ops; the sealed engine replays them) ────────
26
- export const createList = directive("createList")
27
- .creates(TodoList) // Nomos MINTS the id — callers never supply one
28
- .payload(z.object({ title: z.string().min(1) }))
29
- .plan((p) => { create(TodoList).set("title", p.title); return []; });
30
-
31
- export const addTodo = directive("addTodo")
32
- .creates(Todo)
33
- .payload(z.object({ listId: z.string().min(1), text: z.string().min(1) }))
34
- .plan((p) => {
35
- create(Todo).set("listId", p.listId).set("text", p.text).set("done", false);
36
- return [];
37
- });
38
-
39
- export const renameTodo = directive("renameTodo")
40
- .mutates(Todo)
41
- .payload(z.object({ todoId: z.string(), text: z.string().min(1) }))
42
- .plan((p) => [set(instance(Todo, p.todoId), "text", p.text)]);
43
-
44
- // The caller decides done/not-done and rides it IN the payload (a plan is pure — no clock,
45
- // no random). Concurrent toggles are Lww: the later HLC wins, and both peers converge.
46
- export const toggleTodo = directive("toggleTodo")
47
- .mutates(Todo)
48
- .payload(z.object({ todoId: z.string(), done: z.boolean() }))
49
- .plan((p) => [set(instance(Todo, p.todoId), "done", p.done)]);
50
-
51
- // addToSet is the ONLY additive write to an AddWins set (set() would overwrite).
52
- export const tagTodo = directive("tagTodo")
53
- .mutates(Todo)
54
- .payload(z.object({ todoId: z.string(), tags: z.array(z.string()).min(1) }))
55
- .plan((p) => [addToSet(instance(Todo, p.todoId), "tags", p.tags)]);
56
-
57
- // Sharing = ONE native Zanzibar tuple: TodoList:<id>#<role>@user:<user>.
58
- export const shareList = directive("shareList")
59
- .ensures(RelationTuple)
60
- .payload(z.object({
61
- listId: z.string().min(1), userId: z.string().min(1),
62
- role: z.enum(["editor", "viewer"]), sharedBy: z.string().min(1), sharedAt: z.string(),
63
- }))
64
- .plan((p) => writeTuple({
65
- object: `TodoList:${p.listId}`, relation: p.role, subject: `user:${p.userId}`,
66
- grantedBy: p.sharedBy, grantedAt: p.sharedAt,
67
- }));
68
-
69
- // ── what people read (auto-discovered by shape; routed to every peer) ───────────
70
- export const todosByList = query("todosByList").key("listId").returns(Todo);
71
-
72
- // An O(1) maintained tally: how many todos are still open (done = false), per list.
73
- export const openTodosByList = count("openTodosByList")
74
- .of(Todo).where((p) => p.field("done").eq(false)).by("listId");
75
-
76
- // The raw sharing tuples for a list — the audit surface (re-exported so it routes here).
77
- export { relationTuplesByObject };
@@ -1,10 +1,4 @@
1
- // The githolon-compile config: one package, one domain, one module file.
2
- // Read-side declarations (the query + the count) are auto-discovered from the
3
- // module's exports by shape — nothing to wire here. The framework RelationTuple
4
- // aggregate is auto-injected by shareList's `.ensures(RelationTuple)`; todo.ts only
5
- // re-exports the relationTuplesByObject query (the read side).
6
- // Building a Flutter app too? Add `dart: true` for the typed Dart frontend
7
- // (build/dart/) alongside the TS client.
1
+ // The package is just the business-law modules Nomos should compile.
8
2
  export default {
9
3
  name: "__APP_NAME__",
10
4
  domains: [{ key: "todo", modules: ["./domains/todo.ts"] }],
@@ -3,11 +3,10 @@
3
3
  "version": "0.0.0",
4
4
  "private": true,
5
5
  "type": "module",
6
- "description": "A Nomos domain package \u2014 authored in @githolon/dsl, compiled with `githolon compile`, deployed to Nomos Cloud with one POST.",
6
+ "description": "A Nomos business-law package: aggregates, birth, directives, and reads.",
7
7
  "scripts": {
8
8
  "compile": "githolon compile",
9
9
  "proof": "githolon proof",
10
- "e2e": "tsx test/e2e.mts",
11
10
  "typecheck": "tsc --noEmit"
12
11
  },
13
12
  "dependencies": {
@@ -1,57 +0,0 @@
1
- # The mental model
2
-
3
- Five ideas. Everything else in this scaffold is a consequence of them.
4
-
5
- ## Holons
6
-
7
- A holon is the runtime: kernel + SQLite projection + an embedded deterministic
8
- JS engine, compiled into ONE `wasm32-wasip1` artifact. Every peer — the cloud
9
- edge, your laptop, a browser tab, the e2e test — runs the SAME bytes. That is
10
- why results agree: not because peers trust each other, but because they cannot
11
- diverge. There is no "server build" and "client build". There is one build.
12
-
13
- ## Law
14
-
15
- Your domain — aggregates + directives in `domains/*.ts` — compiles to a
16
- package whose sha256 IS its identity (`policy:{hash}`). Law is
17
- content-addressed: a workspace doesn't run "version 3 of guestbook", it runs
18
- `policy:ab12…`, and the generated client carries that exact hash baked in.
19
- A write is judged against the hash it was authored under. No ambient config,
20
- no environment drift — if the bytes differ, it is different law.
21
-
22
- ## Custody, not truth
23
-
24
- The ledger is a git repo. Git stores and transports the chain; it does not
25
- vouch for it. Every holon re-verifies everything it replays: contiguity,
26
- admission of every intent, plans re-run and byte-compared. So possession of
27
- the repo confers nothing — a chain is valid because it verifies, wherever it
28
- sits. This is why `git clone` of your workspace works with stock git, and why
29
- a chain minted on your laptop is exactly as good as one minted in the cloud.
30
-
31
- ## Admission
32
-
33
- Clients author OFFLINE under the pulled law, then push to an untrusted
34
- `session/<clientId>` branch. The edge holon re-admits each intent — validates
35
- the payload, re-runs the plan, byte-compares the result — before merging to
36
- `main`. Verification, never trust: `refs/heads/main` is written only through
37
- that gate. A rejected intent is dead-lettered on both sides, never lost
38
- (see [03-client.md](./03-client.md)).
39
-
40
- ## No server authority
41
-
42
- No holon outranks another. The cloud edge is custody plus a convenient
43
- always-on peer — its verdicts are re-derivable by anyone with the chain and
44
- the wasm. That's the point of Path B in the README: mint a ledger locally,
45
- verify it locally, push it, and watch the cloud re-derive your exact verdict
46
- before serving anything. Authority lives in the git, not in a hostname.
47
-
48
- ## What this buys you
49
-
50
- - Offline is the normal case, not a degraded mode. Writes, queries, counts,
51
- derived fields all run locally; sync is reconciliation, not submission.
52
- - Merges are law, not luck: every field declares its merge driver, so
53
- concurrent edits resolve the same way on every peer
54
- (see [02-authoring.md](./02-authoring.md)).
55
- - The audit trail is `git log`. Every commit is an intent envelope.
56
-
57
- Next: [02-authoring.md](./02-authoring.md) — what you actually write.