geneseed 3.10.0 → 3.12.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.
Files changed (227) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/DESIGN.md +1 -1
  3. package/README.md +27 -45
  4. package/SHIPPED.md +2 -2
  5. package/adapters/bob/README.md +1 -1
  6. package/adapters/claude-code/README.md +17 -12
  7. package/adapters/openclaude/README.md +1 -1
  8. package/adapters/opencode/README.md +4 -4
  9. package/adapters/opencode/plugins/geneseed-guard.js +157 -2
  10. package/bin/build-driver.mjs +2 -0
  11. package/bin/geneseed-cli.mjs +21 -0
  12. package/bin/geneseed-hook.mjs +2 -0
  13. package/docs/README.md +42 -0
  14. package/docs/_groups.json +18 -0
  15. package/docs/concepts/agents.md +44 -0
  16. package/docs/concepts/collaboration.md +62 -0
  17. package/docs/concepts/exclusions.md +55 -0
  18. package/docs/concepts/footprint.md +52 -0
  19. package/docs/concepts/foreman-mode.md +69 -0
  20. package/docs/concepts/hooks.md +101 -0
  21. package/docs/concepts/hosts.md +55 -0
  22. package/docs/concepts/loops.md +165 -0
  23. package/docs/concepts/lsp.md +50 -0
  24. package/docs/{web → concepts}/memory.md +2 -2
  25. package/docs/{web → concepts}/notebook.md +2 -2
  26. package/docs/concepts/rules.md +52 -0
  27. package/docs/concepts/skills.md +49 -0
  28. package/docs/concepts/themes.md +50 -0
  29. package/docs/extending.md +32 -21
  30. package/docs/guides/autostart.md +70 -0
  31. package/docs/guides/choose-your-setup.md +134 -0
  32. package/docs/guides/headless.md +22 -0
  33. package/docs/guides/install.md +161 -0
  34. package/docs/guides/mcp.md +195 -0
  35. package/docs/guides/migrate.md +41 -0
  36. package/docs/guides/project-context.md +87 -0
  37. package/docs/guides/run-anywhere.md +45 -0
  38. package/docs/guides/uninstall.md +51 -0
  39. package/docs/guides/upgrade.md +65 -0
  40. package/docs/guides/verify.md +65 -0
  41. package/docs/guides/wiki.md +69 -0
  42. package/docs/guides/worktree.md +47 -0
  43. package/docs/reference/about.md +7 -0
  44. package/docs/reference/cli.md +7 -0
  45. package/docs/reference/environment.md +99 -0
  46. package/docs/reference/glossary.md +37 -0
  47. package/docs/reference/opencode-plugins.md +133 -0
  48. package/docs/reference/troubleshooting.md +350 -0
  49. package/docs/understand/a-day.md +77 -0
  50. package/docs/understand/enforced-vs-asked.md +64 -0
  51. package/docs/understand/harness.md +36 -0
  52. package/docs/understand/on-your-machine.md +76 -0
  53. package/docs/web-ui.md +13 -2
  54. package/harness.config.json +1 -1
  55. package/js/README.md +27 -4
  56. package/js/build/driver.mjs +14 -8
  57. package/js/build/generate.mjs +22 -7
  58. package/js/build/render.mjs +5 -0
  59. package/js/build/source.mjs +11 -1
  60. package/js/cli-table.json +236 -1
  61. package/js/hosts/gitref.mjs +99 -0
  62. package/js/hosts/hooks.mjs +88 -1
  63. package/js/hosts/installs.mjs +21 -0
  64. package/js/hosts/mcp.mjs +1 -1
  65. package/js/hosts/settings.mjs +13 -1
  66. package/js/inspect/checks-authoring.mjs +15 -3
  67. package/js/inspect/diff.mjs +3 -0
  68. package/js/inspect/doctor.mjs +3 -2
  69. package/js/inspect/inventory.mjs +2 -1
  70. package/js/inspect/registry.mjs +20 -3
  71. package/js/inspect/status.mjs +8 -3
  72. package/js/lib/node-floor.mjs +30 -0
  73. package/js/loop/catalog.mjs +116 -0
  74. package/js/loop/cli.mjs +151 -0
  75. package/js/loop/graph.mjs +145 -0
  76. package/js/loop/score.mjs +143 -0
  77. package/js/loop/state.mjs +322 -0
  78. package/js/maintain/migrate.mjs +4 -2
  79. package/js/maintain/setup.mjs +109 -21
  80. package/js/maintain/update.mjs +4 -15
  81. package/js/ui/cli.mjs +2 -2
  82. package/js/web/actions.mjs +9 -3
  83. package/js/web/api.mjs +41 -2
  84. package/js/web/daemon.mjs +94 -4
  85. package/js/web/docs.mjs +149 -65
  86. package/js/web/handler.mjs +1 -0
  87. package/js/web/jobs.mjs +3 -1
  88. package/js/web/server.mjs +10 -5
  89. package/package.json +6 -4
  90. package/registry.json +21 -0
  91. package/src/AGENT.md.tmpl +6 -0
  92. package/src/bricks/README.md +32 -0
  93. package/src/bricks/_template.md +32 -0
  94. package/src/bricks/apply.md +17 -0
  95. package/src/bricks/baseline-green.md +17 -0
  96. package/src/bricks/bruno-test.md +16 -0
  97. package/src/bricks/ci-fix.md +17 -0
  98. package/src/bricks/deps-audit.md +14 -0
  99. package/src/bricks/docs-update.md +15 -0
  100. package/src/bricks/identify.md +20 -0
  101. package/src/bricks/lint.md +14 -0
  102. package/src/bricks/plan.md +17 -0
  103. package/src/bricks/reproduce.md +16 -0
  104. package/src/bricks/review.md +17 -0
  105. package/src/bricks/security-scan.md +17 -0
  106. package/src/bricks/test.md +14 -0
  107. package/src/doctrines/process.md +11 -8
  108. package/src/loops/bugfix.json +22 -0
  109. package/src/loops/feature.json +21 -0
  110. package/src/loops/refactor.json +20 -0
  111. package/src/postures/mentor.md +1 -0
  112. package/src/skills/brick-forge.md +46 -0
  113. package/src/skills/geneseed.md +1 -1
  114. package/src/skills/learn-mode.md +89 -0
  115. package/src/skills/loop.md +99 -0
  116. package/src/skills/pipeline.md +2 -2
  117. package/src/skills/quiz.md +2 -1
  118. package/src/skills/teach.md +2 -1
  119. package/themes/_TEMPLATE.json +3 -0
  120. package/themes/biker.json +3 -0
  121. package/themes/commentator.json +3 -0
  122. package/themes/cyberpunk.json +3 -0
  123. package/themes/gamer.json +3 -0
  124. package/themes/imperial.json +3 -0
  125. package/themes/joker.json +3 -0
  126. package/themes/marvin.json +3 -0
  127. package/themes/mean.json +3 -0
  128. package/themes/military.json +3 -0
  129. package/themes/neutral.json +3 -0
  130. package/themes/pirate.json +3 -0
  131. package/themes/sports.json +3 -0
  132. package/themes/verstappen.json +3 -0
  133. package/themes/wizard.json +3 -0
  134. package/web/dist/assets/Activity-GaaZWXTY.js +1 -0
  135. package/web/dist/assets/ActivityDetail-4t7d45Du.js +1 -0
  136. package/web/dist/assets/Dashboard-CYn7Tp16.js +2 -0
  137. package/web/dist/assets/Docs-BeFKLg2T.js +5 -0
  138. package/web/dist/assets/{GreenhouseView-D0cbCJ5m.js → GreenhouseView-C6ibc8IE.js} +1 -1
  139. package/web/dist/assets/Installs-DRYjYnxs.js +2 -0
  140. package/web/dist/assets/JournalView-1HbU1mfg.js +1 -0
  141. package/web/dist/assets/Laws-DFoG8JWB.js +3 -0
  142. package/web/dist/assets/Library-DDjgNwz_.js +1 -0
  143. package/web/dist/assets/Loops-D9VEoO0F.js +1 -0
  144. package/web/dist/assets/{Markdown-CkFyfgNf.js → Markdown-qjM2_ofS.js} +5 -5
  145. package/web/dist/assets/{OperatorHudView-CiAkAkQL.js → OperatorHudView-Bs7paWmh.js} +1 -1
  146. package/web/dist/assets/Personal-BY5n4gTw.js +1 -0
  147. package/web/dist/assets/Tabs-ho-EYD8i.js +1 -0
  148. package/web/dist/assets/api-CyMRbU2x.js +1 -0
  149. package/web/dist/assets/drawable-CLS9drMb.js +1 -0
  150. package/web/dist/assets/index-CX_hXMi5.css +1 -0
  151. package/web/dist/assets/index-Cjr7XCA3.js +2 -0
  152. package/web/dist/index.html +3 -2
  153. package/QUICKSTART.md +0 -50
  154. package/SETUP.md +0 -1148
  155. package/docs/web/_groups.json +0 -45
  156. package/docs/web/about.md +0 -6
  157. package/docs/web/adapters-claude-code.md +0 -8
  158. package/docs/web/adapters-opencode-loads.md +0 -8
  159. package/docs/web/adapters-opencode-spec.md +0 -8
  160. package/docs/web/adapters-opencode.md +0 -8
  161. package/docs/web/agents.md +0 -8
  162. package/docs/web/authoring.md +0 -11
  163. package/docs/web/autostart.md +0 -9
  164. package/docs/web/claude-hooks.md +0 -37
  165. package/docs/web/cli.md +0 -6
  166. package/docs/web/collaboration.md +0 -27
  167. package/docs/web/configure-wiki.md +0 -9
  168. package/docs/web/design.md +0 -7
  169. package/docs/web/env-knobs.md +0 -9
  170. package/docs/web/exclusions.md +0 -26
  171. package/docs/web/first-session.md +0 -28
  172. package/docs/web/footprint.md +0 -38
  173. package/docs/web/foreman-mode.md +0 -33
  174. package/docs/web/glossary.md +0 -6
  175. package/docs/web/harnesses.md +0 -30
  176. package/docs/web/headless.md +0 -9
  177. package/docs/web/ingest-docs.md +0 -9
  178. package/docs/web/install-paths.md +0 -9
  179. package/docs/web/install-quick.md +0 -35
  180. package/docs/web/lsp-overview.md +0 -37
  181. package/docs/web/mcp-claude-code.md +0 -10
  182. package/docs/web/mcp-filesystem.md +0 -9
  183. package/docs/web/mcp-gitlab.md +0 -9
  184. package/docs/web/mcp-markitdown.md +0 -9
  185. package/docs/web/mcp-overview.md +0 -34
  186. package/docs/web/mcp-trouble.md +0 -9
  187. package/docs/web/mcp-verify.md +0 -9
  188. package/docs/web/migrate.md +0 -39
  189. package/docs/web/model.md +0 -20
  190. package/docs/web/pipelines.md +0 -24
  191. package/docs/web/plugin-activity.md +0 -23
  192. package/docs/web/plugin-context.md +0 -26
  193. package/docs/web/plugin-guard.md +0 -24
  194. package/docs/web/plugin-learn.md +0 -27
  195. package/docs/web/plugin-notify.md +0 -24
  196. package/docs/web/plugin-ponytail.md +0 -23
  197. package/docs/web/plugin-setup.md +0 -7
  198. package/docs/web/plugin-workflow.md +0 -25
  199. package/docs/web/plugins.md +0 -17
  200. package/docs/web/project-context.md +0 -9
  201. package/docs/web/rules.md +0 -30
  202. package/docs/web/run-anywhere.md +0 -9
  203. package/docs/web/self-improve.md +0 -8
  204. package/docs/web/setup-choices.md +0 -64
  205. package/docs/web/skills.md +0 -8
  206. package/docs/web/themes-author.md +0 -20
  207. package/docs/web/themes.md +0 -9
  208. package/docs/web/token-footprint.md +0 -7
  209. package/docs/web/trouble.md +0 -38
  210. package/docs/web/upgrade.md +0 -9
  211. package/docs/web/verify.md +0 -30
  212. package/docs/web/wiki.md +0 -7
  213. package/docs/web/worktree.md +0 -10
  214. package/docs/wiki.md +0 -43
  215. package/web/dist/assets/Activity-BjVp522q.js +0 -1
  216. package/web/dist/assets/ActivityDetail-8ep1bspW.js +0 -1
  217. package/web/dist/assets/Dashboard-OkC_PCH6.js +0 -2
  218. package/web/dist/assets/Docs-CKPWz00o.js +0 -2
  219. package/web/dist/assets/Installs-BtGGdoTt.js +0 -2
  220. package/web/dist/assets/JournalView-Ckl4dmzR.js +0 -1
  221. package/web/dist/assets/Laws-CLpdRRk8.js +0 -3
  222. package/web/dist/assets/Library-wPPuKQrI.js +0 -1
  223. package/web/dist/assets/Personal-D8CnDo9v.js +0 -1
  224. package/web/dist/assets/Tabs-B4HNrrCs.js +0 -1
  225. package/web/dist/assets/drawable-BiwaOo6x.js +0 -1
  226. package/web/dist/assets/index-C1yil5j1.js +0 -2
  227. package/web/dist/assets/index-CDPDk2vj.css +0 -1
@@ -0,0 +1,165 @@
1
+ ---
2
+ group: concepts
3
+ order: 11
4
+ title: "Loops"
5
+ kind: "concept"
6
+ link: {"hash": "#/docs/reference/cli", "label": "geneseed loop --help →"}
7
+ ---
8
+ A **loop** is a requirement worked as small, validated, committed iterations instead of one long
9
+ turn. `geneseed loop` is the state machine: it decides every transition, ceiling, score and stop,
10
+ and hands the agent one node at a time to run. The `loop` [skill](skills.md) is the only thing
11
+ that talks to it — the agent runs the node it is given and reports the outcome, never its own
12
+ reading of the graph.
13
+
14
+ > **You already know this:** a checklist a tech lead walks through on a ticket, where some steps
15
+ > need a sign-off before continuing and others don't. The lead doesn't improvise the order; the
16
+ > checklist decides it, and only the risky steps stop for you.
17
+
18
+ ## The ring
19
+
20
+ A loop is a graph of **bricks** — one node each — wired by **edges**, one per outcome a brick can
21
+ report. One cycle through the graph back to its head is an **iteration**; the graph's `loops`
22
+ array names every cycle that is allowed to exist, each with a `max` number of times a node inside
23
+ it may be re-entered. Picture it as rings: the outer ring is the iteration itself (plan, apply,
24
+ test, review, back to plan), and inner rings sit inside it for retries (apply failed its test, try
25
+ `apply` again without going all the way back around). The three shipped templates —
26
+ `bugfix`, `feature`, `refactor` — all nest a short `apply`↔`test` retry ring inside the iteration
27
+ ring, and `bugfix` and `feature` nest a second, wider `apply`↔`test`↔`review` ring
28
+ (`review-fix`) around that.
29
+
30
+ Work closes into a commit whenever the graph re-enters the iteration loop's head — so any setup
31
+ work before the loop starts (reproducing a bug, say) is its own unit, numbered iteration 0, kept
32
+ out of iteration 1's diff. For the same reason the iteration has exactly one way in: its
33
+ **head** is the first node listed in the iteration loop (normally `identify`), and every edge that
34
+ enters the iteration from outside it — and `start`, when `start` is inside it — must target that
35
+ head. `geneseed loop check` refuses a graph that enters anywhere else.
36
+
37
+ **A node's re-entry budget is not each loop's `max` added up.** Every node inside one or more
38
+ inner loops gets a single shared counter: `1 + the largest max among the inner loops that contain
39
+ it`. A node in both a `max: 5` and a `max: 3` loop gets 6 re-entries total, not 8 — the loops don't
40
+ stack, the larger one wins and the `+1` is the node's own first run. A node inside no inner loop at
41
+ all gets exactly 1 — no re-entry — which is also why **every cycle inside an iteration must be a
42
+ named inner loop** in the graph JSON: `geneseed loop check` (and `loop init`, which runs the same
43
+ check) refuses a graph with an undeclared cycle inside an iteration, before a single node runs.
44
+
45
+ ## Bricks, templates, and the three origins
46
+
47
+ A **brick** is a markdown file: YAML-ish frontmatter (`name`, `description`, `effect` — `read` or
48
+ `mutate` — exactly one of `agent` or `skill`, and `outcomes`) plus a 4-10 line prose body. The
49
+ model never sees the file; `geneseed loop next` hands it the body as the prompt. A **loop
50
+ template** (`bugfix`, `feature`, `refactor`, or one composed by hand) is the graph JSON that wires
51
+ bricks together.
52
+
53
+ Both are looked up across three origins, each able to override the one before it **by name**:
54
+
55
+ | origin | path | who writes it |
56
+ |---|---|---|
57
+ | shipped | `src/bricks/`, `src/loops/` | Geneseed itself — read by the CLI from its own source, never emitted into an install |
58
+ | global | `$XDG_CONFIG_HOME/geneseed/{bricks,loops}` (default `~/.config/geneseed/…`) | the user, for every project on this machine |
59
+ | project | `<repo>/.geneseed/{bricks,loops}` | a team, committed and shared |
60
+
61
+ Precedence is project > global > shipped. A project or global brick named `apply` replaces the
62
+ shipped `apply` everywhere a template references it, without the template changing.
63
+ `geneseed loop check` lists every override it finds, never silently.
64
+
65
+ A per-install skill exclusion is invisible to the CLI — it has no way to know which skills your
66
+ install carries. The `loop` skill covers the gap itself: when composing a graph it skips a brick
67
+ whose `skill` it doesn't have.
68
+
69
+ To add or adapt a brick, use the `brick-forge` skill — ask it, or see
70
+ [the bricks README](https://github.com/geneseed-dev/geneseed/blob/main/src/bricks/README.md) in
71
+ the repository.
72
+
73
+ ## Risk, trust, and the three validation levels
74
+
75
+ Before a `mutate` brick runs, the loop scores the card the brick's setup declared: one risk weight
76
+ per action kind it named, and the score is the **max**, not a sum — one contract change outweighs
77
+ ten trivial renames, and ten trivial renames never add up to one. After the brick runs, the loop
78
+ re-scores against the real diff, and the diff can only raise the score, never lower it:
79
+
80
+ - a file touched outside the declared write set raises the score to at least **api** (`0.8`);
81
+ - more than 20 deleted lines raises it to at least the **delete** weight;
82
+ - touching a file listed in the loop's `contracts` raises it to at least the **api** weight.
83
+
84
+ `LOOP.md` itself is excluded from every score and every diff check — it's the engine's own
85
+ bookkeeping, rewritten on every action, never part of the work being judged.
86
+
87
+ The score is checked against a **trust preset** — `--preset` on `geneseed loop init`, editable
88
+ afterward in `LOOP.md`'s `preset` field, applying from the next score on:
89
+
90
+ | preset | silent ≤ | soft ≤ | above soft |
91
+ |---|---|---|---|
92
+ | prudent | 0.1 | 0.3 | blocking |
93
+ | balanced (default) | 0.2 | 0.6 | blocking |
94
+ | aggressive | 0.4 | 0.8 | blocking |
95
+
96
+ Three levels follow from where the score lands:
97
+
98
+ - **silent** — nothing more than the commit trailers below.
99
+ - **soft** — listed under "to review" in the run's final summary; no notification during the run.
100
+ - **blocking** — the run ends. `LOOP.md` is written with `status: awaiting`, and a person has to
101
+ answer with `geneseed loop decide --verdict ok|no|amend`. Amending a verdict marks the decision
102
+ `blocking (amended)` in the trailers rather than silently rewriting it to something else.
103
+
104
+ ## `LOOP.md` and its trailers
105
+
106
+ `LOOP.md`, at the worktree root, is both the human-readable record (title, requirement, and the
107
+ rule that you may edit `preset` or `contracts` there) and the engine's own JSON state block. Every
108
+ closing commit carries seven trailers, read straight off that state:
109
+
110
+ ```
111
+ Loop-Iteration: <n>
112
+ Loop-Bricks: <every brick name visited this unit, deduplicated>
113
+ Loop-Risk-Declared: <score>
114
+ Loop-Risk-Actual: <score>
115
+ Loop-Threshold: <preset> <silent>/<soft>
116
+ Loop-Decision: silent | soft | blocking[ (amended)]
117
+ Loop-Tests: <what the loop was told about test state>
118
+ ```
119
+
120
+ ## The `loop/*` branch, and why merge always asks
121
+
122
+ A loop runs in its own worktree, on a branch named `loop/<slug>` — the `loop` skill creates both
123
+ with `git worktree add -b loop/<slug>` before `geneseed loop init` writes `LOOP.md` there.
124
+ While that branch is checked out and `LOOP.md` carries the engine's state marker, the git gate lets
125
+ exactly one commit/push form through without asking:
126
+
127
+ ```
128
+ git add -A && git commit -F <message_file> && git push [-u] <remote> HEAD:<loop branch>
129
+ ```
130
+
131
+ Nothing else is exempt — not `git commit -m`, not a quoted refspec, not a plain `git push` with no
132
+ explicit `HEAD:<ref>` — any other shape still asks. The exemption only ever covers a `loop/*`
133
+ branch, and never a shared one (`main`, `master`, `develop`, `development`, `release/*`,
134
+ `hotfix/*`). The **final** commit of a run — the one that removes `LOOP.md` on `$close` — is
135
+ outside the exemption too, because the loop is no longer running when it lands; that ask is your
136
+ consent to close it. **Merging a loop branch into anything else always asks, with no exception.**
137
+ The loop reports the branch to merge and the iterations that landed in "to review" — it never
138
+ merges for you.
139
+
140
+ ## `geneseed loop` actions
141
+
142
+ | action | what it does |
143
+ |---|---|
144
+ | `check` | lists templates and every brick (available, unavailable, overridden); validates one graph file (`--graph`) or one brick file (`--brick`) |
145
+ | `init` | writes a fresh `LOOP.md` from a template or graph file, under a title, requirement and trust preset |
146
+ | `next` | the only driver of the cycle — returns the next thing to do: run a node, score a card, answer an `awaiting`, or a terminal |
147
+ | `score` | scores a declared card (`--declared`) before a mutate node runs, or the real diff (`--diff`, numstat piped on stdin) before a commit |
148
+ | `record` | records a brick's reported outcome and advances the graph |
149
+ | `decide` | answers an `awaiting` validation with a verdict and a note |
150
+
151
+ Run `geneseed loop --help` for the full flag list.
152
+
153
+ ## Limits
154
+
155
+ - **No parallel nodes.** The graph runs one node at a time; there is no fan-out.
156
+ - **A per-install skill exclusion is invisible to the CLI** (see above) — the `loop` skill is
157
+ responsible for skipping bricks it can't run, not the engine.
158
+
159
+ ## Not foreman mode
160
+
161
+ A loop and a [foreman-mode](foreman-mode.md) pipeline are both "hand work off and keep going," but
162
+ they solve different problems. A pipeline is a one-shot crew for a single task, uncommitted until
163
+ you accept it. A loop is a long-running, self-scoring state machine that commits each validated
164
+ iteration on its own branch as it goes, and only stops for a person when the risk crosses a
165
+ threshold.
@@ -0,0 +1,50 @@
1
+ ---
2
+ group: concepts
3
+ order: 13
4
+ title: "Code intelligence (LSP, OpenCode)"
5
+ kind: "concept"
6
+ ---
7
+ OpenCode can run **language servers** — the same Language Server Protocol servers your editor uses — so the agent sees real diagnostics, type errors and definitions, not just text. Geneseed turns this on for every language OpenCode ships a server for.
8
+
9
+ > **You already know this:** the red squiggles in your editor. With LSP on, the agent gets the same squiggles before it tells you a change is done.
10
+
11
+ ### What is covered
12
+
13
+ | Language | Server | You install |
14
+ | --- | --- | --- |
15
+ | JavaScript, TypeScript, React, React Native | typescript-language-server | nothing — OpenCode downloads it |
16
+ | Python | pyright | nothing — OpenCode downloads it |
17
+ | Java | jdtls | a **JDK 21+** (OpenCode downloads jdtls itself) |
18
+ | SQL | none, on purpose | — |
19
+
20
+ One server covers JavaScript, TypeScript, React and React Native: they are all TS/JS.
21
+
22
+ ### The one prerequisite: Java 21+
23
+
24
+ OpenCode downloads the servers that run on Node by itself on first use. It cannot install a JVM, and jdtls needs one, so `geneseed setup` checks for Java 21+ and prints an install hint if it is missing. Any JDK 21 works, for example:
25
+
26
+ ```bash
27
+ brew install openjdk@21
28
+ ```
29
+
30
+ ```bash
31
+ sdk install java 21-tem
32
+ ```
33
+
34
+ ### Why no SQL server
35
+
36
+ A SQL language server is tied to one dialect — a PostgreSQL server flags Oracle SQL as errors and the other way round — and a `.sql` file can map to only one server, with nothing telling OpenCode which dialect a repo uses. Rather than be wrong for half of all SQL codebases, Geneseed ships none. If your project knows its dialect, add the matching server under the `lsp` key of the project's own `opencode.json`.
37
+
38
+ ### How it is wired
39
+
40
+ The install adds `"lsp": true` to your `opencode.json` (LSP is off in OpenCode by default). If you already have an `lsp` key, Geneseed leaves yours alone.
41
+
42
+ On an air-gapped machine, stop the downloads and pre-install each server yourself:
43
+
44
+ ```bash
45
+ export OPENCODE_DISABLE_LSP_DOWNLOAD=true
46
+ ```
47
+
48
+ ### Verify
49
+
50
+ Open a `.ts` and a `.py` file in a session and ask the agent for diagnostics. The first open triggers the download.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  group: concepts
3
- order: 4
4
- title: "Memory convention"
3
+ order: 6
4
+ title: "Memory"
5
5
  kind: "markdown"
6
6
  source: "src/memory/README.md"
7
7
  ---
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  group: concepts
3
- order: 5
4
- title: "Notebook (sovereign space)"
3
+ order: 7
4
+ title: "Notebook"
5
5
  kind: "markdown"
6
6
  source: "src/notebook/README.md"
7
7
  ---
@@ -0,0 +1,52 @@
1
+ ---
2
+ group: concepts
3
+ order: 2
4
+ title: "Rules (the constitution)"
5
+ kind: "concept"
6
+ link: {"hash": "#/laws", "label": "Browse the constitution →"}
7
+ ---
8
+ The **constitution** is the set of standing rules the agent carries into every session. It is authored in `src/`, rendered into the instructions file your host reads (`AGENT.md`, `CLAUDE.md` or `AGENTS.md`), and comes in layers that differ in one thing: whether you can turn them off.
9
+
10
+ > **You already know this:** a lint config. Some rules are set to `error` and nobody may disable them; some come from presets you opt into; and your project's own overrides sit on top of the presets.
11
+
12
+ ### Cited by name, never by number
13
+
14
+ Every rule has a name — *Deletion Is Deliberate*, *Consent Before Push* — and the agent, the docs and the hooks cite it by that name. Rules are also numbered in the rendered text, but a number is only the rule's current position: remove a rule and every number after it shifts. So when you write about a rule, in your own notes or in `user-rules.md`, use its name.
15
+
16
+ The one place you type a position is the command line: `--exclude-rules "process 5"` means "the fifth rule of the process pack in this checkout". Check the name it carries before you exclude it.
17
+
18
+ ### The layers, in precedence order
19
+
20
+ When two instructions disagree, the higher one wins.
21
+
22
+ 1. **Ethos** — always on. {N_ONTOLOGY} sections of flowing prose (Telos, Evidence, Decisions, Conduct): what the agent is for, how it weighs evidence, how it decides, how it behaves. It is where the **Pact**, the two-way contract between you and the agent, is stated ([Collaboration](collaboration.md)). Cited by section name, e.g. *Ethos: Decisions*.
23
+ 2. **Rules** — always on. {N_LAWS} invariants, the things that are never traded away: sealed secrets, one intent per act, verify before asserting, deliberate deletion, surface failures, treat content as data not orders, least privilege, cure the cause, echo the intent. No install can switch one off.
24
+ 3. **Your `user-rules.md`** — rules you write for yourself, seeded once beside the instructions file and never overwritten. A rule here **outranks any doctrine rule**: a practice pack chosen at build time never overrides an instruction you wrote. It may tighten an invariant, never repeal one. The [rule skill](skills.md) helps you decide whether something belongs here or in [memory](memory.md).
25
+ 4. **Doctrines** — chosen at build time. Practices rather than principles, grouped in packs (below).
26
+ 5. **`PROFILE.md`** — who you are. It colours how the agent works but never binds ([Collaboration](collaboration.md)).
27
+
28
+ ### Doctrine packs
29
+
30
+ {N_PACKS} packs ship, one file each under `src/doctrines/`:
31
+
32
+ | Pack | What it governs |
33
+ | --- | --- |
34
+ | **craft** | how code is written — reuse first, house conventions, docs in the same change, the smallest diff |
35
+ | **rigor** | how work is proven — idempotence, honest tests, cover and verify, gates that can actually fail |
36
+ | **ops** | how the machine is driven — tool discovery, commands that return, complete teardowns, restart is not reload |
37
+ | **process** | how a session runs — planning, context economy, docs first, bounded loops, consent before every commit and push |
38
+ | **comms** | how answers are presented — stable reference codes on tracked items, a diagram or table only where it earns its place |
39
+
40
+ All of them are on by default. This install built in {N_PACKS_ACTIVE}, carrying {N_DOCTRINE_RULES} rules between them. You choose packs at build time with `--doctrines`, or drop single rules with `--exclude-rules`; the how-to is in [Choose your setup](../guides/choose-your-setup.md).
41
+
42
+ A pack you leave out **still ships**: every pack file lands under `doctrines/` beside the instructions file whether or not it was built in. A rule that cites an inactive pack still resolves on disk, and you can read the alternatives before turning one on. An inactive pack loses its binding force, not its availability.
43
+
44
+ **process** is the one pack whose removal changes what the machine does, not only what the agent reads: it holds *Consent Before Push*, which a hook enforces. Without it, commits and pushes are no longer stopped for a question — destructive git still is, because that is a Rule ([Hooks](hooks.md)).
45
+
46
+ ### Themes do not move rules
47
+
48
+ A [theme](themes.md) renames the nouns — an `imperial` install calls the invariants *Dictates* — but the layers, their order and every rule stay exactly where they are.
49
+
50
+ ### Related
51
+
52
+ [Footprint](footprint.md) — how much of this text loads every turn · [Exclusions](exclusions.md) — switching rules off per rule versus per repo · [Glossary](../reference/glossary.md)
@@ -0,0 +1,49 @@
1
+ ---
2
+ group: concepts
3
+ order: 4
4
+ title: "Skills"
5
+ kind: "concept"
6
+ link: {"hash": "#/section/skills", "label": "Browse the catalog →"}
7
+ ---
8
+ A **skill** is a repeatable workflow written as a markdown playbook: when it applies, the steps, and what "done" looks like. The agent reads the playbook before acting, so a task it has a skill for is done the same careful way every time instead of improvised.
9
+
10
+ > **You already know this:** a runbook. Nobody deploys from memory — you open the deploy runbook and follow it. A skill is that runbook, addressed to the agent.
11
+
12
+ {N_SKILLS} skills ship. Each is authored once under `src/skills/` and installed under `skills/` in the install, where the host looks for skills.
13
+
14
+ ### How a skill gets used
15
+
16
+ - **By name.** Ask for it — "brainstorm this", "run a council on it" — or, on hosts with slash commands, type `/<name>`.
17
+ - **By trigger.** Every skill has a one-line description of its purpose and when it applies. The host shows those descriptions to the agent every turn, and the agent opens the matching skill when your request fits.
18
+ - **User-only skills.** A few skills are marked to open only when *you* call them (a teaching drill, a tool tied to a setup the agent cannot see). They answer `/<name>` but the agent never starts them on its own, and their description stays out of the always-loaded list.
19
+
20
+ ### A tour
21
+
22
+ | You want to… | Skill |
23
+ | --- | --- |
24
+ | turn a raw idea into an approved design before any code | `brainstorm` |
25
+ | write a plan to a file before a non-trivial task | `plan` |
26
+ | drive a change through smallest change → tests → green suite | `develop` |
27
+ | find a bug by evidence: reproduce, isolate, root-cause, verify | `debug` |
28
+ | answer a question from the open web, every claim cross-checked | `research` |
29
+ | have several viewpoints debate a decision | `council` |
30
+ | get an adversarial critique of anything | `roast-me` |
31
+ | see what a change does before you agree to commit it | `explain-changes` |
32
+ | stage the right paths and write a focused commit | `commit` |
33
+ | open a pull request, or finish and merge a branch | `ship` |
34
+ | decide whether something is a standing rule or a fact to remember | `rule` |
35
+ | be taught a topic, or quizzed on it | `teach`, `quiz` |
36
+
37
+ The full list, with each description, is in the catalog.
38
+
39
+ ### Skills improve themselves
40
+
41
+ Every skill ends with one beat of reflection: if a step misled or a step was missing, the agent proposes the exact edit to that skill and applies it only with your assent. Most runs end with nothing to change.
42
+
43
+ ### What they cost
44
+
45
+ The skill *bodies* are read only when used. The *descriptions* are listed to the agent every turn so it can pick the right one — that list is part of the always-on cost described in [Footprint](footprint.md).
46
+
47
+ ### Related
48
+
49
+ [Agents](agents.md) — who does the work · [Rules](rules.md) — what every skill obeys · writing your own: [docs/extending.md](../extending.md)
@@ -0,0 +1,50 @@
1
+ ---
2
+ group: concepts
3
+ order: 12
4
+ title: "Themes"
5
+ kind: "concept"
6
+ ---
7
+ A **theme** changes the agent's *voice* and the words the harness uses for its own parts. It never changes structure: the same rules, in the same order, with the same files, folders and links, whatever theme you pick.
8
+
9
+ > **You already know this:** an editor colour scheme. It changes how everything looks, never what the code does.
10
+
11
+ ### What changes and what does not
12
+
13
+ | Changes with the theme | Never changes |
14
+ | --- | --- |
15
+ | how the agent phrases its replies | which rules apply, and their order |
16
+ | the nouns for the harness's parts — an `imperial` install calls the Rules *Dictates*, agents *Adepts*, skills *Rites* | folder names: `agents/`, `skills/`, `memory/`, `laws/`, `doctrines/`… |
17
+ | the banner, the readiness line the agent prints when it starts, the closing lines | section layout and the links between files |
18
+ | the names and descriptions shown for rules, agents and skills | rule addresses such as `process 5` |
19
+
20
+ `neutral` keeps the plain words — Rule, Doctrine, Agent, Skill, Memory — so it is the theme to pick if you want no flavour at all. The [glossary](../reference/glossary.md) shows each themed word beside its neutral one.
21
+
22
+ ### The themes that ship
23
+
24
+ 14 themes ship: `neutral`, `imperial` (Warhammer 40k), `military`, `pirate`, `wizard`, `cyberpunk`, `gamer`, `sports` (play-by-play), `biker`, `commentator`, `joker`, `marvin`, `mean` and `verstappen`.
25
+
26
+ ### Switching
27
+
28
+ The theme is stored in a `.geneseed-theme` marker in the install, so upgrades and rebuilds keep it.
29
+
30
+ - **Setup wizard** — lists every theme with a live preview:
31
+
32
+ ```bash
33
+ geneseed setup
34
+ ```
35
+
36
+ - **Web console** — the per-install voice dropdown on the Harness page.
37
+ - **Command line** — with the emit target of the install you are changing:
38
+
39
+ ```bash
40
+ geneseed build --emit claude-global --theme pirate
41
+ ```
42
+
43
+ <!--harness:opencode-->
44
+ *(OpenCode only)*
45
+ OpenCode also has *colour* themes for its interface. Those are separate from voice themes; `geneseed theme <name>` creates your own colour theme in OpenCode's themes folder, and it survives rebuilds.
46
+ <!--/harness-->
47
+
48
+ ### Writing your own
49
+
50
+ A theme is one JSON file of voice tokens in `themes/`. How the tokens split between voice and structure, and how to add one, is in the maintainer design notes: [DESIGN.md](../../DESIGN.md).
package/docs/extending.md CHANGED
@@ -26,7 +26,7 @@ Three seams, and almost every question about "where do I edit?" resolves to one
26
26
  | Seam | Source of truth | How it reaches a user | Rebuild needed |
27
27
  |---|---|---|---|
28
28
  | **Harness content** | `src/` (laws, agents, skills, memory/notebook conventions, `AGENT.md.tmpl`) + `themes/*.json` for voice | rendered into a bundle by `geneseed build` / `update` / `rebuild-all` | yes — every active install must be re-emitted |
29
- | **Console docs** | `docs/web/*.md` + `docs/web/_groups.json` | read off disk at request time by `js/web/docs.mjs:101` | no — not even a daemon restart for content |
29
+ | **Docs** | `docs/{understand,guides,concepts,reference}/*.md` + `docs/_groups.json` | read on GitHub as plain markdown, and off disk at request time by `js/web/docs.mjs` | no — not even a daemon restart for content |
30
30
  | **Console app** | `web/src/**` | built by vite into the **tracked** `web/dist/` | yes — rebuild *and commit* dist, then `geneseed web restart` |
31
31
 
32
32
  Two rules follow from the table and they cause most of the surprises:
@@ -34,7 +34,7 @@ Two rules follow from the table and they cause most of the surprises:
34
34
  - **Nothing propagates by itself.** A bundle is a *render*. Editing `src/` changes nothing on any
35
35
  machine until something re-emits (`sourceFingerprint` in `js/build/version.mjs` re-fingerprints, `js/inspect/status.mjs`
36
36
  reports the drift).
37
- - **`docs/web/` is data, `web/src/` is code.** A new documentation page is one file and no
37
+ - **`docs/` is data, `web/src/` is code.** A new documentation page is one file and no
38
38
  rebuild. A new screen is a new hashed chunk and a mandatory `web/dist` commit.
39
39
 
40
40
  ### Counts are computed — never type one
@@ -408,10 +408,11 @@ The `geneseed-` prefix and the `.js` suffix are mechanically load-bearing: the b
408
408
  1. `adapters/opencode/plugins/geneseed-<name>.js` — ESM, zero dependencies. The factory-export
409
409
  convention is real (OpenCode requires it) but **ungated**; the only generic gate on plugin
410
410
  source is `node --check` (the one spawn in `authoringProblems`).
411
- 2. `docs/web/plugin-<name>.md` — `group: plugins`, `title: "geneseed-<name>"`, `kind: "concept"`.
412
- 3. `docs/web/plugins.md` — a bullet. The count above it renders from `{N_PLUGINS}`.
413
- 4. `docs/web/model.md` — a second `{N_PLUGINS}` sentence whose **enumeration of the capabilities
414
- is hand-written and ungated**.
411
+ 2. `docs/reference/opencode-plugins.md` — a `## geneseed-<name>` section (gated: every plugin
412
+ file needs one). The count in its intro renders from `{N_PLUGINS}`.
413
+ 3. `docs/understand/on-your-machine.md` — a row in the OpenCode map table (Piece · What it does
414
+ for you · Kind · Cost · Turn it off). **Hand-written and ungated** beyond the table parsing.
415
+ 4. `docs/concepts/hosts.md` — check the capability matrix still tells the truth.
415
416
  5. `README.md` — **three** sites: the badge, the `N plugins` prose, and the 🔌 Plugins row.
416
417
  6. `SHIPPED.md` — the bare name inside `plugins (…)`; that list must equal the directory exactly,
417
418
  in both directions (`tests/unit/web_api.test.mjs:1655`).
@@ -432,14 +433,20 @@ a row to `js/cli-table.json` with a help string over 20 characters.
432
433
 
433
434
  ### 4c — A documentation page
434
435
 
435
- **One file, no rebuild, no server change.** `docs/web/<id>.md`, where the stem is the id.
436
- Frontmatter is JSON-per-value, not YAML (`js/web/docs.mjs:63-82`):
437
-
438
- - `group` must match an id in `_groups.json` — an unknown group is a **silent skip**.
439
- - `kind` ∈ `markdown | concept | glossary | about | cli`; anything else 404s.
440
- - `harness: "claude"|"opencode"` hides the page from the other host. Note the `plugins` group
441
- carries this at the **group** level, and `hooks` symmetrically — a Claude-relevant page dropped
442
- into `plugins` vanishes with no error.
436
+ **One file, no rebuild, no server change.** `docs/<folder>/<id>.md` — folder ∈ understand,
437
+ guides, concepts, reference; the stem is the id and must be unique across folders (a duplicate
438
+ throws). The same file is what GitHub shows, so write for both
439
+ (`tests/unit/docs_tree.test.mjs` gates it). Frontmatter is JSON-per-value, not YAML
440
+ (`docFrontmatter` in `js/web/docs.mjs`):
441
+
442
+ - `group` must match an id in `docs/_groups.json` — gated by `docs_tree.test.mjs`.
443
+ - `kind` ∈ `markdown | concept | map | glossary | about | cli`; anything else 404s. `map` is a
444
+ concept page whose Piece/Kind/Cost table the console turns into the clickable map.
445
+ - `harness: "claude"|"opencode"` hides the page from the other host — keep it for how-tos that
446
+ cannot run elsewhere; a reference page says its host in its title instead.
447
+ - Link pages with relative `.md` links; the console rewrites them to `#/docs/<id>`. A host-only
448
+ passage is `<!--harness:x-->` + a visible `*(OpenCode only)*` / `*(Claude Code only)*` line.
449
+ - No `{N_*}` token in `understand/` or `guides/` — GitHub would show it raw.
443
450
  - `kind: "markdown"` pulls from a repo file via `source:`, traversal-guarded, optionally sliced to
444
451
  one section with `anchor:` + `slice: true`.
445
452
 
@@ -593,7 +600,7 @@ text or flags is now an ordinary edit: `js/cli-table.json` is the owned document
593
600
  holds. Three hand-written equalities still converge on it and are cheap to keep in step — the
594
601
  29-command count and the hidden-argument rule (`tests/unit/cli_table.test.mjs`), and
595
602
  `tests/unit/docs.test.mjs`, which validates every fenced `geneseed <verb> <flags>` line in
596
- `README.md`, `SETUP.md`, `QUICKSTART.md` and `SHIPPED.md` against the table.
603
+ `README.md`, `SHIPPED.md` and every page under `docs/{understand,guides,concepts,reference}/` against the table.
597
604
 
598
605
  ---
599
606
 
@@ -607,8 +614,8 @@ only, at best, on its presence.
607
614
  | `§N` cross-references into `AGENT.md`'s anatomy | `src/skills/*`, `src/agents/*`, `adapters/**` | **range only.** `constitutionProblems` refuses a `§N` the template declares no section for — which catches a pointer past the end, the shape *removing* a section leaves. It cannot catch one that still resolves and now means something else, which is the shape *inserting* a section leaves, and is what actually happened when `## 2. Doctrines` pushed every later section down one. **Renumbering the anatomy means `grep -rn '§' src/ adapters/` and reading every hit.** Four satellites and a live OpenCode deny message shipped stale because the sweep stopped at `AGENT.md.tmpl` |
608
615
  | Per-law Principle lines | `web/src/pages/Laws.jsx` | presence and class only, never accuracy |
609
616
  | 588 themed constitution titles (42 keys × 14 voices) — `LEX_<ID>` (one per law), `DOC_<ID>` (one per doctrine rule), `PACK_<NAME>` | `themes/*.json` | key presence only — a shipped placeholder is green. `LEX_*` and `DOC_*` are held across the template too, and in both directions; `PACK_*` only across the voices |
610
- | The README keyword enumerations | `README.md`, `docs/web/rules.md` | nothing |
611
- | The plugin capability enumeration | `docs/web/model.md` | nothing (the number substitutes; the list does not) |
617
+ | The README keyword enumerations | `README.md`, `docs/concepts/rules.md` | nothing |
618
+ | The per-host map of what lands on a machine | `docs/understand/on-your-machine.md` | table shape only, never accuracy |
612
619
  | Section labels and page subtitles | `web/src/lib/sections.js`, `web/src/pages/Docs/index.jsx` | nothing |
613
620
  | `THEME_BLURBS` (8 of 14), `ART` (8 of 14) | `js/maintain/setup.mjs`, `js/ui/anim.mjs` | nothing — missing entries fall back silently |
614
621
  | `LOADED_SIGIL` uniqueness | `themes/*.json` | nothing, and it is load-bearing for theme detection |
@@ -678,10 +685,9 @@ answer.
678
685
  - **`AGENT_LESSON_PROMPT` has no drift gate.** Its sibling `LEARN_PROMPT_HEAD` is checked for
679
686
  extractability; this one's parity test was retired. Reformat the declaration in
680
687
  `geneseed-learn.js` and the per-agent lesson prompt silently degrades to a two-line fallback.
681
- - **The fenced-command gate still covers only four documents.** `tests/unit/docs.test.mjs`
682
- validates every `geneseed <verb> <flags>` line against `js/cli-table.json` — but only in
683
- `README.md`, `SETUP.md`, `QUICKSTART.md` and `SHIPPED.md`. Adding `DESIGN.md` and the `docs/`
684
- tree to that array is one line, and it would have caught item 2 on the day it was written.
688
+ - **The fenced-command gate skips the maintainer docs.** `tests/unit/docs.test.mjs` validates
689
+ every `geneseed <verb> <flags>` line against `js/cli-table.json` in `README.md`, `SHIPPED.md`
690
+ and the user docs tree — not in `DESIGN.md` or the `docs/*.md` maintainer pages.
685
691
 
686
692
  ---
687
693
 
@@ -742,6 +748,11 @@ handler falls back to `index.html` at 200 with `text/html`, and the browser repo
742
748
  "no running server recorded" and exits 0, and `web restart` starts a *second* daemon. Recovery is
743
749
  to kill every pid on the port, then `geneseed web start`.
744
750
 
751
+ `--port N` on `web stop|restart|status` names *which* daemon: the verb acts only if the record is
752
+ on N, and refuses (exit 1, nothing sent) when it names another port. A test instance on another
753
+ port is therefore stopped with `--port`, never with a bare `web stop` — that one stops whatever
754
+ the record names, usually the live console on 4747.
755
+
745
756
  ---
746
757
 
747
758
  ## 10 — What to settle before the next wave
@@ -0,0 +1,70 @@
1
+ ---
2
+ group: guides
3
+ order: 10
4
+ title: "Start the web console at login"
5
+ kind: "concept"
6
+ ---
7
+ The web console is the only long-running Geneseed process. `geneseed web start` launches it as a background process on `127.0.0.1:4747` and returns immediately. A login item that runs this command once, with `--no-browser`, leaves the console ready whenever you open [http://127.0.0.1:4747](http://127.0.0.1:4747).
8
+
9
+ ```
10
+ geneseed web start --no-browser # start in the background
11
+ geneseed web status # is it running?
12
+ geneseed web stop # stop it (the login item stays)
13
+ geneseed web restart # restart it, e.g. after an update
14
+ ```
15
+
16
+ Only one console runs at a time. A second `start` does nothing, so logging in twice is harmless. Each machine and each user runs its own console on its own loopback address.
17
+
18
+ > **Always use `web start` in a login item, never bare `web`.** Bare `geneseed web` runs in the foreground and leaves no record of itself. `web stop`, `web restart` and `web status` then cannot see it: they report no live server while it keeps serving. A `restart` would then start a second console that cannot take the busy port.
19
+
20
+ > **This is a file you create. Geneseed never writes or edits a login item**, and that includes `geneseed migrate`. To remove the login item, delete the file.
21
+
22
+ The examples below assume `geneseed` is on your `PATH` (see [Run geneseed from anywhere](run-anywhere.md)). Login items do not see your shell's `PATH`, so always use the absolute path to the launcher. For an npm install, `npm prefix -g` shows where npm keeps it.
23
+
24
+ ## Windows
25
+
26
+ Press **Win+R**, type `shell:startup`, and create a file called `geneseed-web.vbs` in the folder that opens:
27
+
28
+ ```vbs
29
+ ' geneseed-web.vbs: start the Geneseed web console at login (hidden, no browser).
30
+ CreateObject("WScript.Shell").Run "cmd /c ""C:\Users\you\AppData\Local\Geneseed\bin\geneseed.cmd"" web start --no-browser", 0, False
31
+ ```
32
+
33
+ Write out the full path, as shown. VBS does not expand `%LOCALAPPDATA%` inside a string. The script runs hidden, so no console window flashes at login. To disable it, delete the file.
34
+
35
+ If you would rather use a scheduled task:
36
+
37
+ ```powershell
38
+ schtasks /Create /TN "Geneseed Web" /SC ONLOGON /TR "\"%LOCALAPPDATA%\Geneseed\bin\geneseed.cmd\" web start --no-browser" /RL LIMITED /F
39
+ schtasks /Delete /TN "Geneseed Web" /F # to remove it
40
+ ```
41
+
42
+ ## macOS
43
+
44
+ Create a LaunchAgent at `~/Library/LaunchAgents/dev.geneseed.web.plist`. Set `RunAtLoad` and **no** `KeepAlive`. The launcher exits as soon as it has started the background process, which keeps running on its own.
45
+
46
+ ```xml
47
+ <?xml version="1.0" encoding="UTF-8"?>
48
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
49
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
50
+ <plist version="1.0">
51
+ <dict>
52
+ <key>Label</key> <string>dev.geneseed.web</string>
53
+ <key>ProgramArguments</key>
54
+ <array>
55
+ <string>/Users/you/.local/bin/geneseed</string>
56
+ <string>web</string>
57
+ <string>start</string>
58
+ <string>--no-browser</string>
59
+ </array>
60
+ <key>RunAtLoad</key> <true/>
61
+ </dict>
62
+ </plist>
63
+ ```
64
+
65
+ `/Users/you/.local/bin/geneseed` is where `./geneseed link` puts the launcher by default. Replace it with your own absolute path. Then load the agent, which also starts the console now:
66
+
67
+ ```bash
68
+ launchctl load ~/Library/LaunchAgents/dev.geneseed.web.plist # enable and start now
69
+ launchctl unload ~/Library/LaunchAgents/dev.geneseed.web.plist # disable
70
+ ```