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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//! Installation-substrate seeding — the `litany prime` verb (ARCH §2.2).
//!
//! [`prime`] idempotently **founds the harness root**: it resolves the
//! config root and data root exactly as every other verb does (via
//! [`crate::harness_root`] — the XDG split, collapsed to one directory by
//! `LITANY_HOME`) and lays down what a ready installation carries — the
//! default `models.yaml` (ARCH §4.2), the `tools/` schema pool and the
//! `skills/` pool (ARCH §3.3), the `workflows/` template pool holding the
//! shipped default (`basic-agentic-loop.yaml`, ARCH §6) beside the named
//! alternative (`learning-loop.yaml`, `docs/DESIGN_LEARNING_LOOP.md` §2)
//! and the empty `workspaces/` directory — **creating what is absent and never clobbering what
//! exists**. `models.yaml` is hand-edited by contract (§4.2), so it is
//! seeded only if absent; every pool entry is likewise seed-if-absent, so
//! a second run changes nothing and a hand-edited entry survives.
//!
//! The shipped assets are **embedded in the binary** at build time (the
//! same `include_dir!` discipline [`crate::template`] uses for the config
//! template), so the `litany` binary is self-contained: seeding a fresh
//! `LITANY_HOME` never reaches back to the source tree. `make install`
//! invokes `litany prime` rather than duplicating the seeding — the verb
//! is the single source of truth for what a ready installation looks like
//! (`docs/PRINCIPLES.md`, single source of truth; §3.4 front door).
use crate;
use crate;
use ;
use fs;
use io;
use ;
/// Config-root subdir holding workflow templates (ARCH §2.2).
const WORKFLOWS_DIR: &str = "workflows";
/// The shipped default workflow's file name in that pool: the **basic
/// agentic loop** (ARCH §6, `docs/TAXONOMY.md` §1), under the name the
/// 2026-08-31 ruling gave it. The bytes are the config template's own
/// `workflow.yaml` — the declaration `litany new` freezes into every
/// `config/default` — so the pool's default entry and the freeze are one
/// asset read twice, never two declarations that can disagree.
const BASIC_AGENTIC_LOOP: &str = "basic-agentic-loop.yaml";
/// The named alternative in that pool: the **learning loop**
/// (`docs/DESIGN_LEARNING_LOOP.md` §2) — the basic agentic loop plus
/// `worker_flush: dispatch(reviewer)` and `reviewer_return:
/// stage_proposal`. Seeded beside the default and never as it: a
/// reviewer is model spend the operator opts into, so adopting it is a
/// config edit (`litany config <ws> learning --from default`, then
/// `litany workflow`), and the basic loop's bytes are untouched
/// (`docs/DESIGN_WORKFLOW_SWITCH.md` §3).
const LEARNING_LOOP: &str = "learning-loop.yaml";
/// Data-root subdir holding the workspaces tree (ARCH §2.2).
const WORKSPACES_DIR: &str = "workspaces";
/// The default global `models.yaml` (ARCH §4.2), embedded verbatim.
const MODELS_YAML: &str = include_str!;
/// The tool JSON-schema pool (ARCH §3.3 point 2), embedded as flat files.
pub static TOOLS: = include_dir!;
/// The skill pool (ARCH §3.3), embedded as `<name>/SKILL.md` directories.
pub static SKILLS: = include_dir!;
/// The learning loop's declaration, embedded verbatim. It is its own
/// asset rather than a derivation of the template's `workflow.yaml`:
/// composing it at seed time would either drop that file's comments (a
/// pool entry an operator copies is read by people) or patch YAML text
/// by hand. The relationship is held instead by
/// `src/install/tests/learning_loop.rs`, which parses both and asserts
/// the difference is exactly the two bindings — so a change to the basic
/// loop that this file should have inherited fails a test rather than
/// drifting silently.
const LEARNING_LOOP_YAML: &str = include_str!;
/// Why [`prime`] could not complete. The only failure is filesystem I/O;
/// the resolver's own failure is the caller's to surface (§3.4).
/// What one [`prime`] run did to the harness root: the seed-if-absent
/// split, counted. It carries no paths — the roots are the caller's own
/// [`Roots`], and re-stating them here would be a second copy of one fact
/// (`docs/PRINCIPLES.md`, single source of truth).
/// Found the harness root (ARCH §2.2), seed-if-absent throughout, and
/// report the split (see [`Founding`]) so the caller can say what it did.
///
/// Idempotent by construction: directories are `create_dir_all` (a no-op
/// when present) and every file is written only when absent, so a second
/// run changes nothing and a hand-edited entry (a curated `models.yaml`,
/// an edited `SKILL.md`) is never clobbered. Under `LITANY_HOME` both
/// roots collapse to one directory and every path below lands there.
/// The basic agentic loop's bytes, read out of the embedded config
/// template rather than embedded a second time — one asset, two seeding
/// paths (the freeze at `litany new`, this pool entry). The template
/// always ships it (`crate::template::TEMPLATE`, pinned by
/// `tests::shipped_template`), so the `None` arm is a programmer error.
/// Recursively seed an embedded directory into `target`, seed-if-absent
/// per leaf file. `target` is the on-disk directory that mirrors `dir`;
/// each embedded file lands at `target/<file-name>`, each embedded subdir
/// recurses into `target/<subdir-name>`. Only files are seed-guarded —
/// directories are `create_dir_all`, so an existing pool with extra
/// entries keeps them and gains only what the binary ships and disk lacks.
/// The final path component of an embedded entry. Embedded paths always
/// have a name (the macro never yields a rootless entry), so the `None`
/// arm is a programmer-error panic, excluded from coverage.
/// Write `bytes` to `path` iff `path` is absent; a present path is left
/// untouched (seed-if-absent — the non-clobber contract, §2.2). Parity
/// with the Makefile's retired `test -e` guard on `models.yaml`. Answers
/// whether it wrote, which is the whole of [`Founding`].
/// `create_dir_all`, mapping the error to [`Error::Io`] with the path.