the_local 0.2.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -1
- data/{lib/the_local/process_rules/develop_process_rules.md → CLAUDE.md} +20 -0
- data/MIGRATING.md +478 -0
- data/PROVIDERS.md +62 -123
- data/README.md +20 -14
- data/lib/generators/the_local/provider_generator.rb +15 -90
- data/lib/the_local/agent.rb +3 -2
- data/lib/the_local/author.rb +43 -0
- data/lib/the_local/creators/develop.md +81 -0
- data/lib/the_local/creators/info.md +67 -0
- data/lib/the_local/creators/install.md +79 -0
- data/lib/the_local/disk_providers.rb +18 -10
- data/lib/the_local/format.rb +27 -0
- data/lib/the_local/front_matter.rb +26 -0
- data/lib/the_local/installer.rb +2 -2
- data/lib/the_local/interface.rb +26 -0
- data/lib/the_local/provider_check.rb +92 -0
- data/lib/the_local/rake.rb +14 -9
- data/lib/the_local/refresh.rb +6 -1
- data/lib/the_local/registry.rb +2 -30
- data/lib/the_local/sync.rb +0 -1
- data/lib/the_local/version.rb +1 -1
- data/lib/the_local.rb +1 -21
- data/the_local/agents/the_local-develop.md +48 -0
- data/the_local/agents/the_local-info.md +40 -0
- data/the_local/agents/the_local-install.md +49 -0
- data/the_local/interface.yml +21 -0
- metadata +16 -15
- data/lib/generators/the_local/templates/guide.md.tt +0 -41
- data/lib/generators/the_local/templates/reference.rb.tt +0 -17
- data/lib/generators/the_local/templates/the_local.rb.tt +0 -49
- data/lib/the_local/builder.rb +0 -57
- data/lib/the_local/process_doc_writer.rb +0 -48
- data/lib/the_local/process_rules.rb +0 -17
- data/lib/the_local/reference/guide.md +0 -179
- data/lib/the_local/reference.rb +0 -16
- data/lib/the_local/the_local/agents/the_local-develop.md +0 -187
- data/lib/the_local/the_local/agents/the_local-info.md +0 -187
- data/lib/the_local/the_local/agents/the_local-install.md +0 -187
- data/lib/the_local/the_local.rb +0 -59
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7e8e6af806f08c3db82c0cd4d2087ca1d09a883e7175c7077e7bd233a2d853a
|
|
4
|
+
data.tar.gz: a44109b99e55bd41534d195a26ae7b01ce5765851573358190e80f009b6b4954
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07ef43635b84f2581ab545563e80145c1ca6aad3d621c36c8236b19492ee566e92885bdfc60afe584499acc7321dbfe798b29b984d4efabe1c1c103951ef8a95
|
|
7
|
+
data.tar.gz: 130fcf910919e1df3e142f8510a5dc02323a200e806bb66407007b39bbffe5d6d88ff705a70b2bf2ddc492b68814eaed327a696ae65ba02bf17f95eb798e9aa2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,42 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [0.4.0] - 2026-07-31
|
|
2
|
+
|
|
3
|
+
- A provider gem ships **no Ruby and no guide**. Its committed
|
|
4
|
+
`the_local/agents/<gem>-{info,install,develop}.md` are authored by
|
|
5
|
+
`rake the_local:author`, which runs the_local's creators against the gem's
|
|
6
|
+
current code — one local at a time — and writes each from it. The creators live
|
|
7
|
+
inside the_local and are never installed into a host.
|
|
8
|
+
- A provider now declares its public interface in **`the_local/interface.yml`**:
|
|
9
|
+
the `scope` line, the entry points assigned to `install` and `develop`, and the
|
|
10
|
+
`sources` that define them. `rake the_local:author` refuses to run without it.
|
|
11
|
+
Deciding what is public is a human's call, made once and committed, instead of a
|
|
12
|
+
judgment the creators re-make on every run.
|
|
13
|
+
- The three locals **never overlap**: `install` hooks the gem into a consumer,
|
|
14
|
+
`develop` covers using it from consuming code, `info` is the read-only catchall.
|
|
15
|
+
One entry point belongs to exactly one local.
|
|
16
|
+
- `rake the_local:check` enforces that contract in both directions — every declared
|
|
17
|
+
entry point documented by its own local, nothing undeclared documented anywhere,
|
|
18
|
+
nothing documented by a local it wasn't declared for — on top of the existing
|
|
19
|
+
front-matter and section checks.
|
|
20
|
+
- Locals are **black-box docs**: they carry the gem's public interface (how, when,
|
|
21
|
+
where, what commands) and never reference its internals or send a reader into the
|
|
22
|
+
provider's source. Their facts come from the code, not from a README that could
|
|
23
|
+
be stale.
|
|
24
|
+
- The deterministic renderer is removed — no `the_local/guide.md`, no
|
|
25
|
+
`rake the_local:build`, no `ProviderBuild`/`Builder`. Install is unchanged: it
|
|
26
|
+
copies committed files off disk verbatim.
|
|
27
|
+
- `the_local:provider` wires the dependency and the Rakefile hook only; it no
|
|
28
|
+
longer scaffolds a guide. `the_local` is its own first provider, with a committed
|
|
29
|
+
manifest its locals are checked against.
|
|
30
|
+
|
|
31
|
+
## [0.3.0] - 2026-07-01
|
|
32
|
+
|
|
33
|
+
- Installing no longer writes a `develop_process_rules.md` into host apps. The
|
|
34
|
+
`ProcessDocWriter`/`ProcessRules` machinery and its bundled doc are removed, so
|
|
35
|
+
`Sync`/`refresh` only install locals and the delegation trigger — a gem's
|
|
36
|
+
process conventions belong in its own guide, not propagated as a shared file.
|
|
37
|
+
- A gem no longer installs its own locals into its own repo: `refresh` excludes
|
|
38
|
+
the gem being run from the direct-dependency set, so a provider working on
|
|
39
|
+
itself doesn't copy its locals back into `.claude/agents/`.
|
|
2
40
|
|
|
3
41
|
## [0.2.0] - 2026-06-20
|
|
4
42
|
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
<!-- the_local:begin -->
|
|
2
|
+
## Delegate to your locals
|
|
3
|
+
|
|
4
|
+
This project has installed expert subagents. Before doing work yourself,
|
|
5
|
+
check whether a local owns it and delegate — never work from memory on
|
|
6
|
+
something a local covers:
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
See each agent's description for specifics.
|
|
11
|
+
<!-- the_local:end -->
|
|
12
|
+
|
|
13
|
+
<!-- the_local:process:begin -->
|
|
14
|
+
Read and follow this develop process for all work in this project. It is
|
|
15
|
+
also written verbatim to `develop_process_rules.md` — reference that file directly.
|
|
16
|
+
|
|
1
17
|
# Develop Process
|
|
2
18
|
|
|
3
19
|
The standard process for writing code across all projects. Default to these rules
|
|
@@ -95,3 +111,7 @@ where touching more than the unit under test is expected and correct.
|
|
|
95
111
|
external bug, a legal/security constraint) and machine-readable annotations the
|
|
96
112
|
tooling requires (e.g. `rubocop:disable`). Prefer refactoring over a "why" comment
|
|
97
113
|
whenever you can.
|
|
114
|
+
<!-- the_local:process:end -->
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
data/MIGRATING.md
ADDED
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
# Migrating a provider gem to the guide-based model
|
|
2
|
+
|
|
3
|
+
> **Superseded.** the_local no longer uses a guide. A provider now ships **no
|
|
4
|
+
> guide and no Ruby** — its committed `the_local/agents/*.md` are authored by the
|
|
5
|
+
> `the_local-author-*` creator agents, which read the gem's current code. To make
|
|
6
|
+
> a gem a provider, or to refresh a stale one, follow **[PROVIDERS.md](PROVIDERS.md)**,
|
|
7
|
+
> not this runbook. This file is kept only for gems still on the old
|
|
8
|
+
> `TheLocal.register` layout that need to reach a committed trio first; once they
|
|
9
|
+
> have one, re-author it with the creators.
|
|
10
|
+
|
|
11
|
+
This is a **deterministic runbook** for converting one provider gem from the old
|
|
12
|
+
`TheLocal.register` layout to the new guide-based one (the_local ≥ the version on
|
|
13
|
+
`main` after PR #72). Follow it top to bottom, **one gem at a time**. Every step
|
|
14
|
+
ends with a **VERIFY** gate; if a gate's actual output does not match the stated
|
|
15
|
+
expectation, **STOP** and resolve it before continuing — do not proceed on a
|
|
16
|
+
failed gate.
|
|
17
|
+
|
|
18
|
+
Do not batch gems. Do not skip verification. Do not invent steps.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Two entry points
|
|
23
|
+
|
|
24
|
+
**Already on the guide model** (the gem has `the_local/guide.md` and no
|
|
25
|
+
`lib/**/the_local.rb`)? Its locals are rendering from the generic template and
|
|
26
|
+
the host agent is not routing to them. Branch first, update the engine, then skip
|
|
27
|
+
to **Step 6 — Author the locals' metadata** and run Steps 7-9:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git checkout main && git pull --ff-only
|
|
31
|
+
git checkout -b chore/author-the-locals
|
|
32
|
+
bundle update the_local
|
|
33
|
+
bundle exec ruby -e 'require "the_local/guide"; puts "ok"' # => ok
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If that prints `LoadError` instead of `ok`, the bundled the_local predates
|
|
37
|
+
authored metadata — **STOP** and point the Gemfile at the_local `main`. Step 6's
|
|
38
|
+
VERIFY needs it.
|
|
39
|
+
|
|
40
|
+
**Still on the register model** (the gem has `lib/<path>/the_local.rb`)? Start at
|
|
41
|
+
the Preconditions and run the whole runbook top to bottom.
|
|
42
|
+
|
|
43
|
+
Either way you finish at the same place: an authored guide, a rebuilt trio, a
|
|
44
|
+
green drift test.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## What the migration changes
|
|
49
|
+
|
|
50
|
+
| Old (register-based) | New (guide-based) |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `lib/<path>/the_local.rb` — `Companion.register!` block | *(deleted)* |
|
|
53
|
+
| `lib/<path>/reference.rb` — `Reference` loader | *(deleted)* |
|
|
54
|
+
| `lib/<path>/reference/guide.md` — the knowledge | **moved to** `the_local/guide.md` (gem root) |
|
|
55
|
+
| `c.agent description:`/`body:`/`scope:` — the authored metadata | **re-authored as** front matter in `the_local/guide.md` (Step 6) |
|
|
56
|
+
| `lib/<path>/the_local/agents/*.md` — committed locals | **rebuilt at** `the_local/agents/*.md` (gem root) |
|
|
57
|
+
| entrypoint `require`/`require_relative "<path>/the_local"` | *(deleted)* |
|
|
58
|
+
| Rakefile `require "<path>/the_local"` before `require "the_local/rake"` | *(deleted; keep the `the_local/rake` line)* |
|
|
59
|
+
| `test/**/companion_test.rb`, `test/**/reference_test.rb` | *(deleted; replaced by a drift test)* |
|
|
60
|
+
|
|
61
|
+
The gem carries **no Ruby** for the_local afterward — one `the_local/guide.md`
|
|
62
|
+
in, the rendered `the_local/agents/*.md` out.
|
|
63
|
+
|
|
64
|
+
`<path>` is the gem's lib subpath: `keystone_ui` for a plain gem,
|
|
65
|
+
`event_engine/subscribers` for a hyphenated gem. The commands below discover it;
|
|
66
|
+
never hardcode it.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Preconditions (run once, at the gem root)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd <the gem's root> # the directory containing *.gemspec
|
|
74
|
+
git checkout main && git pull --ff-only # start clean
|
|
75
|
+
git checkout -b chore/the_local-guide-migration
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**VERIFY** you are in a provider gem on a fresh branch:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ls *.gemspec # exactly one gemspec
|
|
82
|
+
git branch --show-current # chore/the_local-guide-migration
|
|
83
|
+
find lib -path '*/reference/guide.md' # exactly one path — the old guide
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- If there is **no** `*/reference/guide.md`, this gem is not an old-layout
|
|
87
|
+
provider (or already migrated). **STOP.**
|
|
88
|
+
- If there are **two or more**, **STOP** and report — the runbook assumes one.
|
|
89
|
+
|
|
90
|
+
Update to the new the_local so `rake the_local:build` uses the guide-based engine:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bundle update the_local
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**VERIFY** the new engine is present:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
bundle exec ruby -e 'require "the_local/provider_build"; puts "ok"' # => ok
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
If this prints an error instead of `ok`, the bundled the_local is too old.
|
|
103
|
+
**STOP** and fix the dependency (point the Gemfile at the_local `main`).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 1 — Capture the current facts
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
GUIDE=$(find lib -path '*/reference/guide.md') # lib/<path>/reference/guide.md
|
|
111
|
+
LIBPATH=$(dirname "$(dirname "$GUIDE")") # lib/<path>
|
|
112
|
+
GEM=$(basename ./*.gemspec .gemspec) # the gem name
|
|
113
|
+
echo "GUIDE=$GUIDE LIBPATH=$LIBPATH GEM=$GEM"
|
|
114
|
+
echo "-- committed locals today --"; ls "$LIBPATH/the_local/agents/"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**VERIFY** the three variables are non-empty and `$LIBPATH/the_local/agents/`
|
|
118
|
+
lists the current `.md` files.
|
|
119
|
+
|
|
120
|
+
**DECISION — worker facet.** Look at the listed filenames:
|
|
121
|
+
|
|
122
|
+
- If they are `<gem>-info.md`, `<gem>-install.md`, `<gem>-develop.md` → normal
|
|
123
|
+
case, continue.
|
|
124
|
+
- If you see `<gem>-operate.md` (a CLI gem's worker) → the new model renders
|
|
125
|
+
**`develop`**, not `operate`. The migration **renames the worker**: the old
|
|
126
|
+
`operate` local disappears and a `develop` local replaces it. This is a
|
|
127
|
+
deliberate, visible change. Note it for the PR description and continue — the
|
|
128
|
+
old `-operate.md` is deleted in Step 3 and not rebuilt.
|
|
129
|
+
|
|
130
|
+
**GATE — is the guide actually finished?**
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
grep -nE '^[[:space:]]*TODO:' "$GUIDE" || echo "no TODO markers"
|
|
134
|
+
grep -cE '^### (Interface|Recipe|Install|Conventions)' "$GUIDE" # expect 4
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- If there are **any** line-leading `TODO:` markers, or fewer than **4**
|
|
138
|
+
canonical sections, this gem's guide was never finished. The build gate will
|
|
139
|
+
reject it. **STOP.** This is *authoring* work (write the gem's real interface),
|
|
140
|
+
not mechanical migration — do it as a separate, deliberate task, then return.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Step 2 — Move the guide to the gem root
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
mkdir -p the_local
|
|
148
|
+
git mv "$GUIDE" the_local/guide.md
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**VERIFY**:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
test -f the_local/guide.md && echo "moved" # => moved
|
|
155
|
+
test -e "$GUIDE" && echo "STILL THERE — STOP" || echo "old path gone"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Expect `moved` and `old path gone`.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Step 3 — Delete the old Ruby and rendered locals
|
|
163
|
+
|
|
164
|
+
Delete the companion Ruby **first** — that way the require-cleanup in Step 4 sees
|
|
165
|
+
only the two lines that actually need removing, not the soft guard *inside* the
|
|
166
|
+
companion.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
git rm "$LIBPATH/the_local.rb" "$LIBPATH/reference.rb"
|
|
170
|
+
git rm -r "$LIBPATH/the_local/agents"
|
|
171
|
+
# reference/ dir held only the moved guide; remove it if now empty:
|
|
172
|
+
rmdir "$LIBPATH/reference" 2>/dev/null || true
|
|
173
|
+
# Delete the old drift/registration tests if the gem has them:
|
|
174
|
+
find test -name companion_test.rb -o -name reference_test.rb 2>/dev/null | xargs -r git rm
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**VERIFY** the old artifacts are gone:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
ls "$LIBPATH/the_local.rb" "$LIBPATH/reference.rb" 2>/dev/null \
|
|
181
|
+
&& echo "OLD RUBY REMAINS — STOP" || echo "old ruby gone"
|
|
182
|
+
find "$LIBPATH" -path '*the_local/agents*' -name '*.md' | grep . \
|
|
183
|
+
&& echo "OLD AGENTS REMAIN — STOP" || echo "old agents gone"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Expect `old ruby gone` and `old agents gone`.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Step 4 — Remove the companion require from the entrypoint and Rakefile
|
|
191
|
+
|
|
192
|
+
With the companion file already deleted, the gem still *requires* it from two
|
|
193
|
+
places (its entrypoint and its Rakefile). Both requires must go. **Keep**
|
|
194
|
+
`require "the_local/rake"` in the Rakefile.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Every line here is a companion require to delete (rake/builder are excluded):
|
|
198
|
+
grep -rn 'the_local"' lib Rakefile | grep -vE 'the_local/(rake|builder)"'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Edit each file the command prints, deleting the line that requires the companion
|
|
202
|
+
(`require "<path>/the_local"` or `require_relative "<path>/the_local"`), plus any
|
|
203
|
+
now-orphaned comment directly above it. Do **not** delete `require "the_local/rake"`.
|
|
204
|
+
|
|
205
|
+
**VERIFY** no companion require remains, and the rake require survives:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
grep -rn 'the_local"' lib Rakefile | grep -vE 'the_local/(rake|builder)"' \
|
|
209
|
+
&& echo "COMPANION REQUIRE REMAINS — STOP" || echo "entrypoint clean"
|
|
210
|
+
grep -q 'require "the_local/rake"' Rakefile && echo "rake require kept"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Expect `entrypoint clean` and `rake require kept`.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Step 5 — Make the gemspec ship `the_local/`
|
|
218
|
+
|
|
219
|
+
The committed locals now live at the gem root, so the gemspec must include them.
|
|
220
|
+
Check how this gem selects files:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
grep -n 'spec.files' ./*.gemspec
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- **`git ls-files`** based (ships every tracked file) → **no edit needed.** The
|
|
227
|
+
root `the_local/` ships automatically. Skip to VERIFY.
|
|
228
|
+
- **`Dir[...]` / `Dir.chdir { Dir[...] }`** based (an explicit allowlist, e.g.
|
|
229
|
+
`Dir["lib/**/*", "app/**/*"]` or `Dir["{app,config,db,lib}/**/*", ...]`) → the
|
|
230
|
+
root `the_local/` is **not** matched. Edit the glob to add `"the_local/**/*"`
|
|
231
|
+
to the file list.
|
|
232
|
+
|
|
233
|
+
Example edit (keystone_ui-style):
|
|
234
|
+
|
|
235
|
+
```ruby
|
|
236
|
+
# before
|
|
237
|
+
spec.files = Dir["lib/**/*", "app/**/*"]
|
|
238
|
+
# after
|
|
239
|
+
spec.files = Dir["lib/**/*", "app/**/*", "the_local/**/*"]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**VERIFY** the gemspec now includes the guide (once it exists on disk it must be
|
|
243
|
+
selectable). After Step 7 builds the agents, this is re-checked; for now just
|
|
244
|
+
confirm the edit is syntactically valid:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
ruby -e 'Gem::Specification.load(Dir["*.gemspec"].first)' && echo "gemspec loads"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Expect `gemspec loads`. If it errors, **STOP** and fix the syntax.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Step 6 — Author the locals' metadata
|
|
255
|
+
|
|
256
|
+
The register block carried each local's `description` and `body` plus the
|
|
257
|
+
provider's `scope`. **Moving the guide does not carry them over.** Without this
|
|
258
|
+
step every local renders from a generic template — `"Use PROACTIVELY for any
|
|
259
|
+
<gem> work"` — which the host agent only matches if the user already named the
|
|
260
|
+
gem, i.e. exactly when no local was needed. The local never fires and the host
|
|
261
|
+
answers generically. `rake the_local:build` refuses a guide whose scope is
|
|
262
|
+
unauthored, so this step is not optional.
|
|
263
|
+
|
|
264
|
+
**Recover the old wording first.** If this gem had a register block, git history
|
|
265
|
+
holds text that was already authored against the real gem — recover and improve
|
|
266
|
+
it rather than inventing new wording:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
git log --all --oneline -- "$LIBPATH/the_local.rb" | tail -1 # the commit that added it
|
|
270
|
+
git show <that-commit>:"$LIBPATH/the_local.rb" # scope, descriptions, bodies
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
For a gem that never had one, investigate before writing: its gemspec, README,
|
|
274
|
+
public API, tests, and real call sites in consuming projects.
|
|
275
|
+
|
|
276
|
+
Add front matter at the very top of `the_local/guide.md`, above the `## Title`
|
|
277
|
+
line:
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
---
|
|
281
|
+
scope: <domain> — <the tasks this gem owns>
|
|
282
|
+
locals:
|
|
283
|
+
info:
|
|
284
|
+
description: >-
|
|
285
|
+
Use to learn what <gem> offers — <its actual subjects>.
|
|
286
|
+
body: >-
|
|
287
|
+
What this local answers from, and that it changes nothing.
|
|
288
|
+
install:
|
|
289
|
+
description: >-
|
|
290
|
+
Use to add <gem> to a project and set it up correctly.
|
|
291
|
+
body: >-
|
|
292
|
+
The steps it follows, and what it must NOT do (e.g. companion gems).
|
|
293
|
+
develop:
|
|
294
|
+
description: >-
|
|
295
|
+
Use PROACTIVELY for <the real tasks, named> — MUST BE USED instead of
|
|
296
|
+
<the thing people hand-roll>.
|
|
297
|
+
body: >-
|
|
298
|
+
The ceremony that must never be skipped, and what is out of scope.
|
|
299
|
+
---
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Each field answers one question:
|
|
303
|
+
|
|
304
|
+
| Field | Question | Why it matters |
|
|
305
|
+
|---|---|---|
|
|
306
|
+
| `scope` | What user-visible tasks does this gem own? | The one line the host's `CLAUDE.md` delegation rule names. |
|
|
307
|
+
| `description` | What would someone actually ask for? | **The routing surface.** The host agent matches a task against it to decide whether to delegate. |
|
|
308
|
+
| `body` | What ceremony must never be skipped? What is out of scope? | A standing instruction. Facts buried at line 90 of the reference are not instructions. |
|
|
309
|
+
|
|
310
|
+
You author only these. The renderer owns which locals exist, their `tools`, the
|
|
311
|
+
front-matter keys and their order, and the file's structure — do not add a fourth
|
|
312
|
+
local, do not set `tools`, do not invent keys.
|
|
313
|
+
|
|
314
|
+
**GATE — is the `develop` description actually routable?** Read it and answer:
|
|
315
|
+
*would this match a request that never says the gem's name?*
|
|
316
|
+
|
|
317
|
+
- `"Use PROACTIVELY for any event_engine work"` → **broken.** Names only the gem.
|
|
318
|
+
- `"Use PROACTIVELY for any EventEngine work — defining events, choosing
|
|
319
|
+
process_type, emitting, and keeping the committed schema in sync"` → routable.
|
|
320
|
+
Names the tasks.
|
|
321
|
+
|
|
322
|
+
If yours reads like the first, rewrite it before continuing. **This is the whole
|
|
323
|
+
point of the step**; a guide that passes the build gate but fails this question
|
|
324
|
+
ships a local nobody reaches.
|
|
325
|
+
|
|
326
|
+
**VERIFY** the front matter parses and is complete:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
bundle exec ruby -r the_local/guide -e '
|
|
330
|
+
g = TheLocal::Guide.new(File.read("the_local/guide.md"))
|
|
331
|
+
abort "UNAUTHORED SCOPE — STOP" if g.scope.to_s.strip.empty?
|
|
332
|
+
%w[info install develop].each do |n|
|
|
333
|
+
abort "#{n}: no description — STOP" if g.local(n)["description"].to_s.strip.empty?
|
|
334
|
+
end
|
|
335
|
+
abort "TODO markers remain — STOP" if g.scope.include?("TODO")
|
|
336
|
+
puts "authored"
|
|
337
|
+
'
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Expect `authored`. Anything else — fix it before Step 7.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Step 7 — Build the committed locals
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
bundle exec rake the_local:build
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**VERIFY** exactly the standard trio is rendered at the root, and the old worker
|
|
351
|
+
name is gone:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
ls the_local/agents/ # <gem>-info.md <gem>-install.md <gem>-develop.md
|
|
355
|
+
ls the_local/agents/*-operate.md 2>/dev/null && echo "OPERATE STILL PRESENT — STOP" || echo "no operate file"
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
- Expect three files: `<gem>-info.md`, `<gem>-install.md`, `<gem>-develop.md`.
|
|
359
|
+
- If `rake the_local:build` **fails** with `incomplete guide(s)` → the guide has
|
|
360
|
+
a `TODO:` or is missing a section. Return to Step 1's GATE. **STOP.**
|
|
361
|
+
|
|
362
|
+
**VERIFY the build is idempotent** (a second build produces no diff):
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
bundle exec rake the_local:build
|
|
366
|
+
git status --short the_local/agents/ # expect NO output
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Any output here means the build is non-deterministic — **STOP** and report.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Step 8 — Add a drift test
|
|
374
|
+
|
|
375
|
+
Create a test that fails if a future edit to the guide isn't rebuilt. Adapt the
|
|
376
|
+
path and test framework to the gem (Minitest shown; the gem root is the dir with
|
|
377
|
+
the gemspec).
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
# test/the_local_drift_test.rb (or spec/the_local_drift_spec.rb)
|
|
381
|
+
# frozen_string_literal: true
|
|
382
|
+
|
|
383
|
+
require "test_helper"
|
|
384
|
+
require "the_local/provider_build"
|
|
385
|
+
|
|
386
|
+
class TheLocalDriftTest < Minitest::Test
|
|
387
|
+
def test_committed_agents_match_the_rendered_build
|
|
388
|
+
gem_root = File.expand_path("..", __dir__)
|
|
389
|
+
TheLocal::ProviderBuild.new(gem_root).agents.each do |agent|
|
|
390
|
+
assert_equal agent.to_markdown, File.read(agent.source_path)
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Adjust `File.expand_path("..", __dir__)` so it resolves to the gem root from the
|
|
397
|
+
test file's location (one `..` per directory level of the test file below root).
|
|
398
|
+
|
|
399
|
+
**VERIFY** the gem's whole suite passes:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
bundle exec rake test # or: bundle exec rspec
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Expect **0 failures, 0 errors**. If the drift test fails, the committed agents
|
|
406
|
+
don't match the build — re-run Step 7. If other tests fail because they
|
|
407
|
+
referenced the deleted companion/reference, delete or rewrite those assertions
|
|
408
|
+
(they tested removed code).
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Step 9 — Lint, review, commit, PR
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
bundle exec rubocop # if the gem uses it — expect clean
|
|
416
|
+
git status --short # review every add/delete/modify
|
|
417
|
+
git diff --stat main
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**VERIFY** the diff contains only: the guide move, deleted companion/reference/old
|
|
421
|
+
agents, the entrypoint + Rakefile edits, the gemspec edit (unless git-ls-files),
|
|
422
|
+
the new `the_local/agents/*.md`, and the drift test. Anything else — **STOP** and
|
|
423
|
+
explain it before committing.
|
|
424
|
+
|
|
425
|
+
Commit in small, honest steps, then open a PR against the gem's `main`:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
git add -A
|
|
429
|
+
git commit -m "Migrate to the guide-based the_local provider model"
|
|
430
|
+
git push -u origin chore/the_local-guide-migration
|
|
431
|
+
gh pr create --base main --title "Migrate to the guide-based the_local provider model" --body "…"
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
In the PR body, state plainly:
|
|
435
|
+
- The gem now ships no Ruby for the_local; one `the_local/guide.md` renders the
|
|
436
|
+
locals.
|
|
437
|
+
- **If this was an `operate` gem:** the worker local is renamed `operate` →
|
|
438
|
+
`develop`. Hosts that installed `<gem>-operate.md` keep a stale copy until they
|
|
439
|
+
re-run `the_local install`; note that a host re-sync is needed.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## The six gems and their specifics (ground truth)
|
|
444
|
+
|
|
445
|
+
Verified against the repos on disk. Use this to sanity-check what each gem's run
|
|
446
|
+
should look like — but still run every VERIFY gate; do not skip them.
|
|
447
|
+
|
|
448
|
+
**Check which entry point each gem needs before starting it** — a gem migrated
|
|
449
|
+
before the authoring step existed has an unauthored guide and needs Step 6
|
|
450
|
+
onward, not the whole runbook:
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
test -f the_local/guide.md && ! ls lib/**/the_local.rb >/dev/null 2>&1 \
|
|
454
|
+
&& echo "already migrated — start at Step 6" || echo "register model — start at Preconditions"
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
| Gem | lib `<path>` | Worker | gemspec `files` | gemspec edit? | Old comp/ref tests | Notes |
|
|
458
|
+
|---|---|---|---|---|---|---|
|
|
459
|
+
| `citizen` | `citizen` | develop | `Dir.chdir { Dir["{app,config,db,lib}/**/*", …] }` | **yes** — add `"the_local/**/*"` | none | clean |
|
|
460
|
+
| `cs133` | `cs133` | develop | `git ls-files` | **no** | none | clean |
|
|
461
|
+
| `dash_kit` | `dash_kit` | develop | `Dir.chdir { Dir["{app,config,db,lib}/**/*", …] }` | **yes** | none | clean |
|
|
462
|
+
| `event_engine` | `event_engine` | develop | `Dir.chdir { Dir["{app,config,db,lib}/**/*", …] }` | **yes** | **companion_test + reference_test** — delete both | **already migrated (PR #238) with an unauthored guide — start at Step 6.** Its old register block holds the authored text to recover. |
|
|
463
|
+
| `event_engine-subscribers` | `event_engine/subscribers` | **operate** | `Dir.chdir { Dir["{app,config,db,lib}/**/*", …] }` | **yes** | none | **guide is all `TODO:` — unfinished scaffold. Step 1 GATE will STOP you: finish the guide first (authoring), or skip this gem.** |
|
|
464
|
+
| `keystone_ui` | `keystone_ui` | develop | `Dir["lib/**/*", "app/**/*"]` | **yes** | **companion_test + reference_test** — delete both | clean |
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Fail-safe summary
|
|
469
|
+
|
|
470
|
+
Stop and get help the moment any of these is true:
|
|
471
|
+
|
|
472
|
+
- A VERIFY gate's output doesn't match its stated expectation.
|
|
473
|
+
- The guide has `TODO:` markers or fewer than 4 canonical sections.
|
|
474
|
+
- `rake the_local:build` reports `incomplete guide(s)` or `unauthored scope`.
|
|
475
|
+
- A `develop` description names only the gem ("any `<gem>` work") — it will not route.
|
|
476
|
+
- A second build produces a diff (non-idempotent).
|
|
477
|
+
- The final `git diff --stat` shows files outside the expected set.
|
|
478
|
+
- The gem's test suite has failures you can't trace to deleted companion/reference code.
|