1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! **A layer host.** A layer is one independent shared space between participants, named
//! `urn:layer:{layer}`: its definition (a file in the host's configuration) chooses an
//! ACCESS MODEL, names its closed SHACL admission shapes and its egress context, and its
//! grants are capabilities named for it (`urn:cap:layer:{verb}:{layer}`). It has its own
//! gapless feed. Adding a layer whose model exists is configuration, never code.
//!
//! A collaboration is a MANIFEST (`urn:collab:{name}`): which layers it mounts and which
//! participant holds which verbs on each. The door's enrollment (cli's `grants.json` and
//! `clients.json`) is generated from the manifests ([`grants`], and the `ikigai-layers
//! grants <config dir>` binary), so the manifest is the one thing an operator edits.
//!
//! This version builds two access models: `channel` (append-only entries, one graph per
//! author) and `tuplespace` (offers taken atomically, reports addressed to their offerer,
//! with receipts; see [`tuplespace`]).
//!
//! On those two, a GATEWAY between kernels is configuration plus a reference participant
//! ([`gateway`]): an ask layer per asker carries requests and their answers (a representation,
//! or a typed error), and an event channel per resource owner carries invalidations.
//!
//! Every answer a participant reads also has a JSON face ([`json`]), so a participant with
//! only an HTTP client and a JSON parser can take part: a graph as the layer's egress context,
//! pruned and compacted, always one top-level `@graph` array (`as=application/ld+json`), and a
//! list or a write's answer as plain JSON (`as=application/json`).
//!
//! ```text
//! urn:layer:{layer} Source the definition (ik:Layer) read:{layer}
//! urn:layer:{layer}:shapes Source the closed admission shapes read:{layer}
//! urn:layer:{layer}:context Source the egress context (JSON-LD) read:{layer}
//! urn:layer:{layer}:feed Source events after= (wait= ≤ 60 s) feed:{layer}
//! urn:layer:{layer}:say Sink append one entry, answer its IRI say:{layer}
//! urn:layer:{layer}:entries Source entries after= from= type= read:{layer}
//! urn:layer:{layer}:entry:{id} Source one entry (never changes) read:{layer}
//! urn:layer:{layer}:graph:{slug} Source one author's entries read:{layer}
//! urn:layer:{layer}:latest Source newest entry about= not superseded read:{layer}
//! urn:layer:{layer}:tuples Sink out: drop one tuple, its subject out:{layer}
//! Source rd: pending tuples, or receipts read:{layer}
//! Delete take: one tuple, atomically take:{layer}
//! urn:layer:{layer}:receipt:{id} Source one take (never changes) read:{layer}
//! urn:layers:feed Source one wait over several feeds feed:{each layer}
//! urn:layers:participants Source who each principal is layers:read:participants
//! urn:layers:me Source who the door says the caller is collab:read:* (any grant)
//! urn:collab:{name} Source a manifest collab:read:{name}
//! urn:collab:{name}:participants Source who takes part in it collab:read:{name}
//! ```
//!
//! (Capabilities abbreviated: `read:{layer}` is `urn:cap:layer:read:{layer}`.)
//!
//! # A host library
//!
//! No binary serves anything: a host (ikigai-cli's `serve`, ledger #1188) opens a [`Host`]
//! over its configuration and state directories and binds [`space`] with a clock (every
//! entry is stamped with the kernel's time). The door mints each connection's principal;
//! `say`, `out` and `take` refuse a request that carries none.
//!
//! **The layer space is all a door binds.** Admission validates with ikigai-shacl, which
//! this crate links and calls itself, so the door's kernel needs no `urn:shacl:validate`,
//! and binding one beside would offer it to every participant: it declares no capability
//! (ledger #1266). **One host per state directory**: [`Host::open`] locks it, and refuses
//! while another host holds it (ledger #1267).
//!
//! ```
//! use std::sync::Arc;
//! use ikigai_core::{Kernel, SystemClock};
//!
//! # let dir = std::env::temp_dir().join(format!("ikigai-layers-doc-{}", std::process::id()));
//! # let (config, state) = (dir.join("config"), dir.join("state"));
//! # std::fs::create_dir_all(&config).unwrap();
//! let host = ikigai_layers::Host::open(&config, &state).expect("a configuration that checks");
//! let kernel = Kernel::new(Arc::new(ikigai_layers::space(&host))).with_clock(Arc::new(SystemClock));
//! // A second host over the same state directory is refused while this one lives.
//! assert!(ikigai_layers::Host::open(&config, &state).is_err());
//! # drop(kernel);
//! # drop(host);
//! # std::fs::remove_dir_all(&dir).unwrap();
//! ```
//!
//! # Isolation
//!
//! Separate channels, separate workflows, no overlap unless decided (Brian, 2026-10-10). A
//! layer belongs to ONE collaboration unless its definition says `shared = [..]` naming
//! every collaboration that mounts it; a manifest that breaks this is refused when the host
//! opens and when the generator runs, so no generated grant reaches another
//! collaboration's layer. See [`config::load_collabs`].
//!
//! # What this crate never writes
//!
//! `ik:layer` (lowercase) is a dry run's chain cell with `rdfs:domain ik:Consultation`;
//! writing it would type the subject a consultation. A layer is an `ik:Layer`, and the
//! layer an entry belongs to is the `{layer}` segment of its own IRI.
pub use ;
pub use space;
pub use Host;
/// The README's examples, compiled so they cannot rot.
;