@@ -0,0 +1,760 @@
1+# How to write a jet
2+
3+A guide for new Urbit developers.
4+
5+Problem statement: coder A has written some hoon, and you - coder B - need to jet it.
6+
7+Preconditions:
8+
9+* You have a pill `jetted.pill`, located in ~/tlon.
10+* You have an example of hoon code that, executed in dojo, does the right thing.
11+
12+## Get all the source code you need.
13+
14+The source code you will need to modify lives in two different repos:
15+urbit and arvo. The urbit repo has the source code for the
16+intrepretter / personal server, written in C. The arvo repo has the
17+operating system, written in hoon. Since you're jetting the hoon, you
18+need to modify both.
19+
20+For simplicitly, I'm going to assume that you are doing all of your
21+development in ~/tlon. This saves the bother of writing nonsense like
22+the/path/to/your/sandbox, and also means that one can copy-and-paste
23+these instructions straight into a terminal with zero editing. Do
24+your development elsewhere, if you like, and make a symbolic link.
25+
26+1. mkdir ~/tlon
27+1. cd ~/tlon
28+1. git clone https://github.com/urbit/urbit
29+1. cd urbit
30+1. git fetch
31+1. git checkout <branch> # optional
32+1. scripts/bootstrap
33+1.
34+1. cd ..
35+1. git clone https://github.com/urbit/arvo
36+1. cd arvo
37+1. git fetch
38+1. git checkout <branch> # optional
39+1. cd ..
40+
41+## Add new subprojects / libraries to urbit, if necessary
42+
43+If we have a complicated hoon function that, say, computes square
44+roots, we need to speed it up, and there is an open source library
45+libsquareroots, adding libsquareroots to our build might solve 90% of
46+our problems.
47+
48+If this describes your task, read this section. If not, skip to the next section - none of this is necessary.
49+
50+1. have someone with github.com/urbit repo privileges fork libsquareroots into github.com/urbit
51+1. fork this new repo github.com/urbit/libsquareroots
52+1. cd ~tlon/urbit/subprojects
53+1. git submodule add <url>
54+1. edit ~tlon/urbit/subprojects/meson.build
55+ 1. add a line `<foo>_dep = dependency('<foo>', version: '>=0.1.0', fallback: ['<foo>', '<foo>_dep'])`
56+ 1. add `<foo>_dep` to the list of dependencies at the bottom of the file. Remember to use a comma.
57+1. generate a meson.build for the new subproject: cd subprojects/<new directory>; meson wrap promote subprojects/secp256k1
58+1. edit the meson.build until it works ("works" is defined as "in the top level ~/tlon/urbit invoking scripts/build builds the library and links it into the urbit executable")
59+1. git add meson.build ; git commit -m"now builds with meson for Tlon" .
60+1. cd .. ; git add .gitmodules ; git commit -m"added submodule" .
61+1. test the whole thing by
62+ 1. cd /tmp
63+ 1. rm -rf urbit
64+ 1. git clone https://github.com/<yourname>/urbit
65+ 1. cd urbit
66+ 1. scripts/bootstrap
67+ 1. verify that the new submodule is present
68+ 1. scripts/build
69+ 1. verify that the urbit executable is built and linked to the new library
70+1. submit a pull request from your copy of <libsquareroots> to the urbit copy
71+1. submit a pull request from your copy of urbit to the urbit copy
72+
73+### If the submodule is modified
74+
75+The steps above add a submodule to the urbit repo. Or, more specifically, they add a specific version of the submodule to the repo.
76+
77+If the submodule has commits made to it (perhaps, the urbit repo will not track those new commits. XXXX)
78+
79+
80+## Edit the source code
81+
82+There are several things you're going to do:
83+
84+1. hint the hoon code, so that the urbit interpreter will know to look for C code
85+1. for each jet you want you're going to declare two functions in two .h files (one takes the arguments as separate arguments, one takes them as one big tree)
86+1. then implement the two C functions in a single .c file
87+1. register the new C jet functions so the urbit interpretter knows the names / function pointers of the C funcs
88+
89+
90+### Edit the Hoon Source code
91+
92+Let's edit the hoon source code first.
93+
94+There are multiple runes to do hinting, but we're going to concentrate
95+on three. All hinting runes start with a tilda ("sig"). A mnemonic
96+is "we're signalling some information to the interpretter".
97+
98+1. ~/ sigfas: simple jet registration, using defaults for some arguments
99+1. ~% sigcen: more complicated jet registration, specifying all arguments
100+1. ~& sigpam: debugging printf
101+
102+Feel free to use ~& liberally! (Just remove them when you're done).
103+
104+Let's use the three to jet some code. Starting with this example:
105+```
106+ ++ aaa
107+ ...
108+ ++ bbb
109+ ++ ccc
110+ |= dat=@
111+ ^- pont
112+ =+ x=(end 3 w a)
113+ =+ y=:(add (pow x 3) (mul a x) b)
114+ =+ s=(rsh 3 32 dat)
115+ :- x
116+ ?: =(0x2 s) y
117+ ?: =(0x3 s) y
118+ ~| [`@ux`s `@ux`dat]
119+ !!
120+```
121+
122+our steps are:
123+
124+1. add a line under `++ aaa` like this: `~% %aaa ..is ~`
125+1. add a line under `++ bbb` like this: `~/ %bbb`
126+1. add a line under `++ ccc` like this: `~/ %ccc`
127+
128+What we're doing here is hinting `ccc`, and then adding a string of
129+hints up the enclosing tree of arms. Each of these hints is
130+implemented w the simple / minimalist `~/` rune, which takes one
131+argument: the symbol that should be used to label the hint (these
132+symbols will be used later in the C code to match up C code with hoon code).
133+
134+The top hint (for `aaa`) uses the more verbose `~%` hint syntax, which
135+specifies two additional fields: `...is` means "parent jet can not be
136+determined by context, so use 'is' as the parent" ("is" is the name of a system-supplied jet).
137+
138+[ N.B. saying " `is` is the parent " is a quick-and-dirty lie. The
139+fuller version is: `+is` is an arm of the Arvo core, so `..is` is a
140+reference to the entire Arvo core. The whole Arvo core is hinted with
141+the jet label `%hex`, which is used as the parent for all the
142+top-level jet hints in %zuse. ]
143+
144+When hinting your own code, make sure to hint each nesting arm.
145+Skipping any one will result in the jet code not being run.
146+
147+Note that you do not need to provide C implementations for everything
148+you hint. In this above example we hint aaa, bbb, and ccc - even if
149+our intent is only to jet ccc.
150+
151+### Edit the C Source code (overview)
152+
153+Having hinted our hoon, we now need to write the matching C code. If
154+we don't, there isn't a problem - hinting code merely tells the
155+interpretter to look for a jet, but if a jet is not found, the hoon
156+still runs just fine.
157+
158+There are two distinct tasks to be done in C:
159+1. write the jet
160+1. register the jet
161+
162+For each jet you will write one u3we() function and one u3qe() function.
163+
164+### Edit the C Source code to add registration
165+
166+* edit the header file
167+ include/jets/w.h
168+ to have a declaration for each of your u3we() functions. Every u3we() function looks the same, e.g.
169+ u3_noun u3we_xxx(u3_noun);
170+
171+* edit the header file
172+ ~/tlon/urbit/include/jets/q.h
173+
174+ to have a declaration for your u3qe() function. u3qe() functions
175+ can differ from each other, taking distinct numbers of u3_nouns and/or u3_atoms, e.g
176+
177+ u3_noun u3qe_yyy(u3_atom, u3_atom);
178+ u3_noun u3qe_zzz(u3_noun, u3_noun, u3_atom, u3_atom);
179+
180+* create a new .c file to hold your jets (both the u3we_() and u3qe_() functions go in the same file). For example, ~/tlon/urbit/jets/e/secp.c
181+ (The choice of subdirectory under 'jets' (a through g) is XXX )
182+ The new file should have three things:
183+ 1. \#include "all.h"
184+ 1. the new u3we() function
185+ 1. the new u3qe() function
186+
187+* edit ~/tlon/urbit/jets/tree.c to register jet
188+
189+In the hoon code we hinted some leaf node functions (`ccc` in our example) and then hinted each parent node up to the root `aaa`).
190+
191+We need to replicate this structure in C. Here's example C code to jet our above example Hoon:
192+
193+```
194+ // 1: register a C func u3we_ccc()
195+ static u3j_harm _143_hex_hobo_reco_d[] =
196+ {
197+ {".2", u3we_ccc, c3y},
198+ {}
199+ };
200+
201+ // 2: that implements a jet for hoon arm 'ccc'
202+ static u3j_core _143_hex_hobo_bbb_d[] =
203+ {
204+ { "ccc", _143_hex_hobo_ccc_d },
205+ {}
206+ };
207+
208+ // 3: ... that is inside a hoon arm 'bbb'
209+ static u3j_core _143_hex_hobo_hobo_d[] =
210+ {
211+ { "bbb", 0, _143_hex_hobo_bbb_d },
212+ {}
213+ };
214+
215+ // 4: ... that is inside a hoon arm 'aaa'
216+ static u3j_core _143_hex_d[] =
217+ { { "down", 0, _143_hex_down_d },
218+ { "lore", _143_hex_lore_a },
219+ { "loss", _143_hex_loss_a },
220+ { "lune", _143_hex_lune_a },
221+ { "coed", 0, _143_hex_coed_d },
222+ { "aes", 0, _143_hex_aes_d },
223+ { "hmac", 0, _143_hex_hmac_d },
224+ { "aaa", 0, _143_hex_hobo_d },
225+ {}
226+ };
227+
228+```
229+
230+There are 4 things steps here. Let's look at each in turn.
231+
232+Section 1 names the C function that we want to invoke: 'u3we_ccc()'.
233+The precise manner in which it does this is by putting entries in an
234+array of 'u3j_harm's. The first one specifies the jet; the second one
235+is empty and serves as a termination to the array, similar to how a C
236+string is null terminated with a zero. The jet registration supplies
237+two fields {".2", u3we_secp}, but this does not initialize all of the
238+fields of u3j_harm. Other fields can be specified.
239+
240+The first field, with value ".2" in this example, is "arm 2".
241+
242+[ N.B. ".2" labels the axis of the arm in the core. With a %fast hint
243+(~/), we're hinting a gate, so the relevant arm formula is always just
244+the entire battery at +2. I assume the jet dashboard is flexible
245+enough to hint arms at different axes, but I've never seen it done. ]
246+
247+The second field, with value u3we_secp in this example, is a function
248+pointer (to the C implementation of the jet).
249+
250+The third field (absent here) is a flag to turn on verification of C
251+jet vs hoon at run time. It can take value c3n (which means verify at run time) or c3y
252+(which means don't verify). If not present, it is set to don't verify.
253+
254+[N.B. The use of the flags seems inverted. Why is c3y ("yes") used to
255+turn OFF verification? A: because the flag is actually "is the jet
256+already known to be perfect?" ]
257+
258+There are additional flags; see ~/tlon/urbit/include/noun/jets.h
259+
260+
261+Section 2 associated the previous jet registration with the name
262+"ccc". Note that this is the symbol used in the Hoon hint! Note also
263+that we again have a "null terminated" (metaphorically) list, ending with `{}`.
264+
265+Section 3 references structure built in step 2 and slots it under
266+`bbb` (again, note that this is exactly the same symbol used in the
267+hinting in Hoon).
268+
269+The line in section 2
270+```
271+ { "ccc", _143_hex_hobo_ccc_a },
272+```
273+
274+looks very similar to the line in section 3
275+```
276+ { "bbb", 0, _143_hex_hobo_bbb_d },
277+```
278+
279+But note that the line in section 2 fill in the first 2 fields in the
280+struct, and the line in section 3 fills in the first three fields.
281+Section 2 is registering an array of u3j_harm, i.e. is registering an actual C
282+jet.
283+
284+Section 3 is specifying 0 for the array of u3j_harm and is instead
285+specifying an array of u3j_core, i.e. it is registering nesting of
286+another core which is not a leaf node.
287+
288+Section 4 is much like section 3, but it's the root of this particular
289+tree. Section 4 is also an example of how a given node in the
290+jet-registration tree may have multiple children.
291+
292+Using this example you should be able to register jets whether your
293+nesting is 2 layers deep, 3 (like this example), or more. You should
294+also be able to register multiple jets at the same nesting level (e.g.
295+a function u3we_ddd() which is a sibling of u3we_ccc() inside data structure _143_hex_hobo_reco_d[] ).
296+
297+
298+### Edit the C source code to add the u3we_() function
299+
300+There are two C functions per jet, because separation of concerns is a good thing.
301+
302+The first C function - named u3we_something() - unpacks arguments from
303+the Hoon code and gets them ready.
304+
305+The second C function - named u3qe_something() - takes those arguments
306+and actually performs the operations that parallel the hoon code being
307+jetted.
308+
309+Let's write the u3we_() function.
310+
311+Your function is going to accept one argument, of type u3_noun. This
312+is the same type as a hoon noun ('*').
313+
314+This one argument is the payload.
315+
316+The payload is a tree, obviously.
317+
318+The payload consists of (on the right branch) the context (you'd think
319+of "global variables and available methods", if analogies to other
320+programming languages were allowed!) and on the left branch the
321+sample (the arguments to this particular function call).
322+
323+Your u3we_() function does one thing: unpack the sample from 'cor',
324+sanity check them, and pass them in to the u3qe_() function.
325+
326+To unpack the sample
327+
328+We use the function u3r_mean() to do this, thusly:
329+
330+ u3_noun arg_a, arg_b, arg_c ... ;
331+
332+ u3r_mean(cor,
333+ axis_a, & arg_a,
334+ axis_b, & arg_b,
335+ axis_c, & arg_c
336+ ...
337+ 0)
338+
339+
340+If we want to to assign the data located at axis 3 of cor to arg_a, we'd set axis_a = 3.
341+
342+u3r_mean() takes varargs, so we can pass in as many axis /
343+return-argument pairs as we wish, terminated with a 0.
344+
345+When pulling arguments out of a hoon remember that Nock and Hoon store
346+lists as skinny right-descending trees (because a linked list is a
347+degenerate case of a tree).
348+
349+The quick way to figure out axis locations is to remember that we
350+start with axis 1, and left children have axis 2n and right children
351+have axis 2n+1.
352+
353+If one argument is passed in, it is found at axis 1.
354+
355+If we have two arguments, axis 1 holds pointers to the first argument
356+in the left child at axis 2 (when n is 1, 2n = 2 ) and the second
357+arguments in the right child at axis 3 (when n is 1, 2n+1 is 3).
358+
359+If we have three arguments, axis 1 holds pointers to the first
360+argument in the left child at axis 2 (when n is 1, 2n = 2 ) and to the
361+next cell at 3, which doesn't contain an argument, but points to
362+argument 2 in the left child at axis 6 (when n is 3, 2n = 6) and to
363+argument 3 in the right child at axis 7 (when n is 3, 2n + 1 = 7).
364+
365+Note that there are #defines to help you specify the axises you want.
366+They are in include/noun/xtract.h
367+
368+If the sample has one item, that one item it is located at the axis
369+specified by the #define u3x_sam_1.
370+
371+If the sample has 2 items, they are located at the axis specified by
372+the #defines u3x_sam_2 and u3x_sam_3.
373+
374+If the sample has 3 items, they are located at the axis specified by
375+the #defines u3x_sam_2, u3x_sam_6, and u3x_sam_7.
376+
377+etc.
378+
379+If you have four arguments and want to tease them out and verify them, you could use code like this
380+
381+N.B. in our fprintf()s we're using both \n and \r to achieve line feed
382+(move cursor down one line) and carriage return (move it to the left),
383+because Urbit uses ncurses to control the screen and it changes the
384+default behavior you may be used to (where \n accomplishes both).
385+```
386+ c3_o ret;
387+ u3_noun sample;
388+ ret = u3r_mean(cor, u3x_sam_1, &sample, 0);
389+ fprintf(stderr, "ret = %i\n\r", ret); // we want ret = 0 = yes
390+ u3m_p("sample", sample); // pretty print the entire sample
391+
392+ ret = u3r_mean(cor, u3x_sam_2, &sample, 0);
393+ fprintf(stderr, "ret = %i\n\r", ret);
394+ u3m_p("2: ", sample);
395+
396+ ret = u3r_mean(cor, u3x_sam_6, &sample, 0);
397+ fprintf(stderr, "ret = %i\n\r", ret);
398+ u3m_p("6: ", sample);
399+
400+ ret = u3r_mean(cor, u3x_sam_14, &sample, 0);
401+ fprintf(stderr, "ret = %i\n\r", ret);
402+ u3m_p("14: ", sample);
403+
404+ ret = u3r_mean(cor, u3x_sam_15, &sample, 0);
405+ fprintf(stderr, "ret = %i\n\r", ret);
406+ u3m_p("15: ", sample);
407+```
408+
409+If the hoon that you're jetting looks like this
410+```
411+ ++ make-k
412+ ~/ %make-k
413+ =, mimes:html
414+ |= [aaa=@ bbb=@ ccc=@]
415+```
416+In the C code you'd fetch them out of the payload with
417+```
418+ u3r_mean(cor,
419+ u3x_sam_2, & arg_aaa,
420+ u3x_sam_5, & arg_bbb,
421+ u3x_sam_6, & arg_ccc
422+ ...
423+ 0)
424+```
425+If you're confident, go ahead and write code. If you want to inspect
426+your arguments to see what's going on, you can pretty print the
427+sample.
428+
429+You could - IN THEORY - inspect / pretty-print the noun by calling
430+```
431+ u3m_p("description", cor); :: DO NOT DO THIS !!!
432+```
433+...but you don't want to do this, because, recall, cor contains the
434+entire context - the whole enchilada.
435+
436+Do instead, perhaps,
437+```
438+ c3_o ret;
439+ u3_noun sample;
440+
441+ ret = u3r_mean(sample, u3x_sam_1, &sample, 0);
442+ fprintf(stderr, "ret = %i\n\r", ret); // we want ret = 0 = yes
443+ u3m_p("sample", sample); // pretty print the entire sample
444+```
445+
446+After our C function pulls out the arguments it needs to type check them.
447+
448+If arg_a is supposed to be a atom, trust but verify:
449+```
450+ u3ud(arg_a); // checks for atomicity; alias for u3a_is_atom()
451+```
452+If it's supposed to be a cell:
453+```
454+ u3du(arg_a); // checks for cell-ness
455+```
456+There are other tests you might need to use
457+```
458+ u3a_is_cat()
459+ u3a_is_dog()
460+
461+ u3a_is_pug()
462+ u3a_is_pom()
463+```
464+All of these rests return Hoon loobeans (yes/no vs true / false), so
465+check return values vs c3n / c3y. If any of these u3_mean(), u3ud()
466+etc return u3n you have an error and should return
467+```
468+ return u3m_bail(c3__exit);
469+```
470+otherwise pass the arguments into your "inner" jet function and return the results of that.
471+
472+### Edit the C source code to add the u3qe_() function
473+
474+The u3qe_() function is the "real" jet - the C code that replaces the hoon.
475+
476+First, you may need to massage your inputs a bit to get them into types that you can use.
477+
478+You have received a bunch of u3_nouns or u3_atoms, but you presumably want to do
479+things in a native C / non-Hoon manner: computing w raw integers, etc.
480+
481+A u3_noun will want to be further diassembled into atoms. XXX
482+
483+A u3_atom represents a simple number, but the implementation may or
484+may not be simple. If the value held in the atom is 31 bits or less,
485+it's stored directly in the atom. If the value is 32 bits the atom
486+holds a pointer into the loom where the actual value is stored. ( see https://urbit.org/docs/vere/nouns/ )
487+
488+You don't want to get bogged down in the details of this - you just
489+want to get data out of your atoms.
490+
491+If you know that the data fits in 32 bits or less, you can use
492+```
493+ u3r_word(c3_w a_w, u3_atom b);
494+```
495+
496+If it is longer than 32 bits, use
497+```
498+ u3r_words(c3_w a_w, c3_w b_w, c3_w* c_w, u3_atom d);
499+```
500+
501+or
502+```
503+ u3r_bytes(c3_w a_w, c3_w b_w, c3_y* c_y, u3_atom d)
504+```
505+
506+(N.B. You may want to use u3r_bytes regardless, as
507+
508+The actual meat of the function is up to you. What is it supposed to do?
509+
510+Now we move on to return semantics.
511+
512+First, you can transfer raw values into nouns using
513+```
514+ u3_noun u3i_words(c3_w a_w, const c3_w* b_w)
515+```
516+and you can build cells out of nouns using
517+```
518+ u3nc(); // pair
519+ u3nt(); // triple
520+ u3nq(); // quad
521+
522+```
523+There are two facets here: (i) data format, (ii) memory allocation.
524+
525+Regarding data format, if the hoon is expected to return a single atom (e.g. if the hoon looks like this
526+```
527+ ++ make-k
528+ ~/ %make-k
529+ |= [has=@uvI prv=@] :: <---- input parguments
530+ ^- @ :: <---- return value is a single value of type '@' (atom)
531+ ...
532+```
533+then your C code - at least when you're stubbing it out - can do something like
534+```
535+ return(123);
536+```
537+Or, if you want to create an atom more formally, you can build it like this
538+```
539+ // this variable is on the stack and will disappear
540+ unsigned char nonce32[32];
541+
542+ // this allocates an indirect (> 31 bits) atom in the loom,
543+ // does appropriate reference count, and returns the 32 bit handle to the atom
544+ u3_noun nonce = u3i_words(8, (const c3_w*) nonce32);
545+
546+ // this returns the 32 bit handle to the atom
547+ return(nonce);
548+```
549+If, on the other hand, your hoon looks like
550+```
551+ ++ ecdsa-raw-sign :: generate signature
552+ ~/ %ecdsa-raw-sign
553+ |= [has=@uvI prv=@]
554+ ^- [v=@ r=@ s=@]
555+ ...
556+```
557+ending your C code with
558+```
559+ return(123);
560+```
561+is wrong and will result in a dojo error because you are returning a single atom, instead of a list of three atoms.
562+
563+Instead do one of these:
564+```
565+ return(u3nc(a, b)); // for two atoms
566+ return(u3nt(a, b, c)); // for three atoms
567+ return(u3nq(a, b, c, d)); // for four atoms
568+```
569+If you need to return a longer list, you can compose your own. Look
570+at the definitions of these three functions and you will see that they
571+are just recursive calls to the cell constructor u3i_cell() e.g.
572+```
573+ u3i_cell(a, u3i_cell(b, u3i_cell(c, d));
574+```
575+
576+XXX more here about memory model, allocation, ownership
577+
578+
579+
580+## Compile the C code
581+
582+You've edited C code; now you need to compile it to build a new urbit executable!
583+
584+
585+1. cd ~/tlon/urbit
586+1. rm -rf build
587+1. configure: choose one of
588+ 1. meson configure -Dbuildtype=release build
589+ 1. meson configure -Dbuildtype=debugoptimized build
590+ 1. meson configure -Dbuildtype=debug build
591+ Note that debugoptimized builds run slower than release builds, and debug builds run slower yet. Booting a debug builkd of urbit may take several minutes. [ N.B. compiler flags -O2 vs -O3 ]
592+1. scripts/build
593+
594+## Compile the Hoon code into a pill
595+
596+You've compiled the Hoon code. Now you need to compile it.
597+
598+Wait, compile? Isn't Hoon that one types at the dojo prompt interpretted, or compiled on the fly?
599+
600+Yes. But.
601+
602+When the urbit executable runs the first thing it does is load the
603+complete arvo operating system. That step is much faster if it can
604+load a "jam"-ed "pill", where all of the hoon has already been parsed
605+from text file into Hoon abstract syntax tree, and then compiled from
606+the hoon into the Nock equivalent.
607+
608+Note that this means that if you edit hoon.hoon, zuse.hoon, arvo.hoon,
609+vane/ames.hoon, etc. and then restart the urbit executable **YOU ARE
610+NOT RUNNING YOUR NEW CODE**.
611+
612+The only way to run the new code is to follow the following process:
613+
614+1. start up urbit, tell it to be a fake zod (act as a galaxy and disconnect from the rest of the network) and have it know where your edited arvo files are (although not execute them, as discussed above):
615+ 1. rm -rf ~/zod
616+ 1. rm -rf ~/tlon/mypill.pill
617+ 1. ~/tlon/urbit/build/urbit -FI zod -A ~/bus/tlon/arvo/ -c zod
618+ This should take < 90 seconds.
619+ 1. If you accidentally exit urbit you can restart it XXX
620+1. inside your urbit, from the dojo command line, load the hoon files and compile them into a pill file:
621+ 1. .pill +solid
622+ This should take < 90 seconds.
623+ 1. examine the output. Expect to see something like this
624+ ```
625+ %solid-start
626+ %solid-loaded
627+ %solid-parsed
628+ %solid-compiled
629+ %solid-arvo
630+ [%solid-kernel 0x6aa7.627e]
631+ %arvo-assembly
632+ [%solid-veer p=%$ q=/zuse]
633+ [%tang /~zod/home/~2018.7.25..20.47.51..0027/sys/zuse ~mondyr-rovmes]
634+ ```
635+ 1. if, on the contrary, you see anything like this:
636+ ```
637+ syntax error
638+ {3,356 7}
639+ /~zod/home/~2018.7.25..20.47.51..0027/sys/zuse
640+ ```
641+ you have an error. In this case the error is on line 3,356, character 7 of file ~/tlon/arvo/sys/zuse.hoon.
642+
643+
644+ 1. the urbit executable will not reload the .hoon files as you edit them. Neither `|reset` nor `.pill +solid` will make edits visible. Instead do this:
645+ 1. in dojo: `|mount /=base=`
646+ 1. in dojo: `|autoload %.y`
647+ 1. at the command line : `ln -s ~/tlon/arvo/sys/zuse.hoon ~/zod/base/sys/zuse.hoon ` (make changes to both arguments of the ln command if you're editing, say, base/sys/vane/ford.hoon)
648+ This does three things: it makes urbit's file system mount your own, it makes urbit scan its own filesystem for changes and load them automatically, and it keeps your zuse.hoon
649+ Make a change to the hoon file. In dojo you should see `<<sync>>`. If you do not, one of the above steps was done incorrectly. If you do see this, it will be followed by any compile errors.
650+ 1. Edit the hoon and try again. Keep iterating until the hoon compiles.
651+1. exit urbit with control-D
652+1. save the pill file
653+ 1. cp ~/zod/.urb/put.pill ~/tlon/mypill.pill
654+
655+[ N.B. another take on explaining the above:
656+
657+Here's some things to note about the pill (and -A):
658+
659+An urbit has to boot into the Arvo kernel -- a nock core with a
660+particular interface. It'd be possible to make some ad-hoc procedure
661+to initialize Arvo, but it would be a pretty drastic layering
662+violation and couple urbit to all sorts of internal implementation
663+details of Arvo and Hoon. In contrast, the pill is basically a
664+serialized, declarative set of steps to initialize Arvo.
665+
666+Right now, the boot process is something of a hack, and the pill is
667+basically a snapshot of a pristine Arvo kernel. In the future (see
668++metal or +brass), the pill will contain something like:
669+
670+1. a boot formula
671+1. the hoon compiler as nock
672+1. the hoon compiler as source
673+1. arvo as source
674+1. the vanes as source
675+1. userspace as source (ie, an initial %clay sync)
676+
677+For now, when you boot a ship that's not a galaxy, the initial %clay
678+filesystem is synced in from the parent ship. When you boot a galaxy,
679+you need to pass in a path to a copy of the Arvo repository so that
680+the %clay filesystem can be initialized without recourse to another
681+ship.
682+
683+Hopefully this helps to demystify these startup procedures.
684+
685+]
686+
687+
688+## Run the compiled C / compiled Hoon pill
689+
690+1. type `cd ~`
691+1. type `rm -rf zod`
692+1. type `~/tlon/urbit/build/urbit -FI zod -A ~/tlon/arvo/ -B ~/tlon/mypill.pill -c zod`.
693+
694+ N.B. booting should not take more than about 90 seconds. If it
695+ goes longer than that you might have created a 'poison pill', which
696+ hangs things. Try booting without the -B flag, and/or reverting
697+ your hoon changes, generating a new pill based on that, and
698+ launching urbit with the known-clean pill. If these steps and boot
699+ in < 90 seconds, but a boot with a pill created from your own hoon
700+ does not, you have a hoon bug of some sort.
701+
702+ Hoon bugs that disable booting can be as simple as the wrong number
703+ of spaces. Many, but not all of them, will result in compile
704+ errors during the `.pill +solid` step. If your booting takes > 90
705+ seconds, abort it, and look at your hoon. Do a git diff, and
706+ remove half the edits. Run through the entire process again. If
707+ booting from the pill still hangs, remove half of what remains. Do
708+ a binary search to find the precise error.
709+
710+1. inside dojo: `|reset`
711+1. You now have created a galaxy fakezod, on its own detached network, running your own strange variant of the OS.
712+1. inside dojo: `(make-k:secp256k1:secp:crypto `@uvI`12 33)` # or whatever command runs the hoon you're jetting
713+1. do your development work
714+1. If you happen to exit, you can restart with
715+ `urbit -FI zod zod`
716+
717+To expand:
718+* F means "fake"
719+* I means "run as galaxy zod"
720+* the final argument is the unix directory holding the files for the galaxy
721+
722+## Run the jetted code and compare to the non jetted code
723+
724+You are now running your jetted code in a fake zod.
725+
726+It would be convenient to fire up a second urbit in a terminal next to your fake zod, this one using non-jetted hoon.
727+
728+Then you can run identical commands in each, in parallel, and confirm that they do the same thing.
729+
730+1. edit ~/tlon/urbit/jets/e/secp.c (or whatever) to include `fprintf(stderr, "*** u3we_sign 2\n");`
731+(or similar) in your jetted functions. This will let us verify that the jets exist and are running.
732+1. `cd ~/tlon/ubit ; scripts/build `
733+
734+1. `cp ~/tlon/arvo ~/tlon/arvo_nojet`
735+
736+1. edit ~/tlon/arvo_nojet/sys/zuse_nojetting.hoon to remove jetting
737+
738+1. Because we can not run two instances of the same fake galaxy on the
739+same machine (their ports would conflict), we need to pick a new
740+galaxy name. Galaxy names are not arbitrary. You may not name your
741+galaxy "mygalaxy", "withjet", "withoutjet", or anything like that.
742+Galaxy names are restricted to the range 0-255, converted into
743+pronounceable syllables. 'Zod' is just the pronunciation of '0' ( to
744+see this, in a dojo, cast ~zod to an untyped atom thusly: `@`~zod).
745+Let's pick 1 as our new galaxy id. Use dojo to convert this into a
746+urbit name: `@p`1 yields ~nec.
747+
748+1. Open a new terminal. In that terminal: `cd ~ ; rm -rf nec ; ~/tlon/urbit/build/urbit -FI nec -A ~/tlon/arvo_nojetting/ -c nec`
749+1. This should take < 90 seconds.
750+1. inside your urbit, from the dojo command line, load the hoon files and compile them into a pill file:
751+ ` .pill +solid`
752+1. This should take < 90 seconds.
753+1. exit urbit with control-D
754+1. save the pill file
755+1. type `cp ~/nec/.urb/put.pill ~/tlon/mypill_nojetting.pill `
756+1. type `cd ~`
757+1. type `rm -rf nec`
758+1. type `~/tlon/urbit/build/urbit -FI nec -A ~/tlon/arvo_nojetting/ -B ~/tlon/mypill_nojetting.pill -c nec`
759+
760+