PageSourceSearch

https://zhubert.com/erg/

html zhubert.com collected 2026-09-25 00:42:00 UTC 35,271 bytes, 1,364 lines download raw bytes

1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6    <title>erg - workflow-driven agent orchestrator for Claude Code</title>
7    <meta
8      name="description"
9      content="erg — workflow-driven agent orchestrator for Claude Code."
10    />
11    <link rel="preconnect" href="https://fonts.googleapis.com" />
12    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
13    <link
14      href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],400;12..96,500;12..96,600;12..96,700;12..96,800&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600&display=swap"
15      rel="stylesheet"
16    />
17    <link rel="stylesheet" href="sim-dashboard.css" />
18    <style>
19      :root {
20        --bg: #141416;
21        --bg-sidebar: #0f0f11;
22        --bg-card: #1e1e21;
23        --bg-code: #1a1a1d;
24        --bg-inset: #111113;
25        --accent: #f97316;
26        --accent-dim: #ea580c;
27        --accent-bg: rgba(249, 115, 22, 0.08);
28        --accent-border: rgba(249, 115, 22, 0.2);
29        --cyan: #22d3ee;
30        --green: #34d399;
31        --violet: #a78bfa;
32        --text: #e4e4e7;
33        --text-muted: #a1a1aa;
34        --text-dim: #71717a;
35        --border: #2a2a2e;
36        --border-light: #3f3f46;
37      }
38
39      * {
40        margin: 0;
41        padding: 0;
42        box-sizing: border-box;
43      }
44
45      html {
46        font-size: 100%;
47        scroll-behavior: smooth;
48        scroll-padding-top: 2rem;
49      }
50
51      body {
52        font-family:
53          "IBM Plex Sans",
54          -apple-system,
55          sans-serif;
56        background: var(--bg);
57        color: var(--text);
58        line-height: 1.7;
59        min-height: 100vh;
60        -webkit-font-smoothing: antialiased;
61        -webkit-text-size-adjust: 100%;
62        text-size-adjust: 100%;
63      }
64
65      ::selection {
66        background: var(--accent);
67        color: #fff;
68      }
69
70      h1,
71      h2,
72      h3,
73      h4 {
74        font-family: "Bricolage Grotesque", sans-serif;
75        letter-spacing: -0.02em;
76      }
77
78      code,
79      pre {
80        font-family: "IBM Plex Mono", monospace;
81      }
82
83      a {
84        color: var(--accent);
85        text-decoration: none;
86      }
87
88      a:hover {
89        text-decoration: underline;
90      }
91
92      /* ---- Two-column layout ---- */
93
94      .page {
95        display: flex;
96        min-height: 100vh;
97      }
98
99      /* ---- Sidebar ---- */
100
101      .sidebar {
102        width: 15rem;
103        flex-shrink: 0;
104        background: var(--bg-sidebar);
105        border-right: 1px solid var(--border);
106        position: sticky;
107        top: 0;
108        height: 100vh;
109        overflow-y: auto;
110        padding: 1.5rem 0;
111        display: flex;
112        flex-direction: column;
113      }
114
115      .sidebar-logo {
116        padding: 0 1.25rem;
117        margin-bottom: 1.75rem;
118      }
119
120      .sidebar-logo a {
121        font-family: "Bricolage Grotesque", sans-serif;
122        font-size: 2rem;
123        font-weight: 800;
124        color: var(--text);
125        text-decoration: none;
126        letter-spacing: -0.03em;
127      }
128
129      .sidebar-logo a span {
130        color: var(--accent);
131      }
132
133      .sidebar-nav {
134        list-style: none;
135        flex: 1;
136      }
137
138      .sidebar-section {
139        margin-bottom: 0.25rem;
140      }
141
142      .sidebar-section-title {
143        display: block;
144        padding: 0.4rem 1.25rem;
145        font-size: 0.7rem;
146        font-weight: 600;
147        text-transform: uppercase;
148        letter-spacing: 0.08em;
149        color: var(--text-dim);
150        margin-top: 0.75rem;
151      }
152
153      .sidebar-link {
154        display: block;
155        padding: 0.35rem 1.25rem 0.35rem 1.75rem;
156        font-size: 0.85rem;
157        color: var(--text-muted);
158        text-decoration: none;
159        transition:
160          color 0.15s,
161          background 0.15s;
162        border-left: 2px solid transparent;
163      }
164
165      .sidebar-link:hover {
166        color: var(--text);
167        background: rgba(255, 255, 255, 0.03);
168        text-decoration: none;
169      }
170
171      .sidebar-link.active {
172        color: var(--accent);
173        border-left-color: var(--accent);
174        background: var(--accent-bg);
175      }
176
177      .sidebar-footer {
178        padding: 1rem 1.25rem 0;
179        border-top: 1px solid var(--border);
180        margin-top: auto;
181      }
182
183      .sidebar-footer a {
184        display: block;
185        font-size: 0.78rem;
186        color: var(--text-dim);
187        padding: 0.2rem 0;
188        text-decoration: none;
189      }
190
191      .sidebar-footer a:hover {
192        color: var(--text-muted);
193        text-decoration: none;
194      }
195
196      /* ---- Main content ---- */
197
198      .main {
199        flex: 1;
200        min-width: 0;
201        max-width: 920px;
202        padding: 2.5rem 3rem 4rem;
203      }
204
205      /* ---- Content typography ---- */
206
207      .main h1 {
208        font-size: 2.5rem;
209        font-weight: 800;
210        color: var(--text);
211        margin-bottom: 0.75rem;
212      }
213
214      .main h2 {
215        font-size: 1.4rem;
216        font-weight: 700;
217        color: var(--text);
218        margin-top: 3.5rem;
219        margin-bottom: 1rem;
220        padding-top: 1.5rem;
221        border-top: 1px solid var(--border);
222      }
223
224      .main h2:first-of-type {
225        margin-top: 2.5rem;
226      }
227
228      .main h3 {
229        font-size: 1.1rem;
230        font-weight: 600;
231        color: var(--text);
232        margin-top: 2rem;
233        margin-bottom: 0.5rem;
234      }
235
236      .main h4 {
237        font-size: 0.95rem;
238        font-weight: 600;
239        color: var(--text);
240        margin-top: 1.5rem;
241        margin-bottom: 0.4rem;
242      }
243
244      .main p {
245        margin-bottom: 1rem;
246        color: var(--text-muted);
247      }
248
249      .main p code,
250      .main li code {
251        background: var(--bg-code);
252        color: var(--cyan);
253        padding: 0.15rem 0.4rem;
254        border-radius: 4px;
255        font-size: 0.85em;
256        border: 1px solid var(--border);
257      }
258
259      .main ul,
260      .main ol {
261        margin-bottom: 1rem;
262        padding-left: 1.5rem;
263        color: var(--text-muted);
264      }
265
266      .main li {
267        margin-bottom: 0.35rem;
268        font-size: 0.95rem;
269      }
270
271      /* ---- Hero area ---- */
272
273      .hero-badge {
274        display: inline-block;
275        font-family: "IBM Plex Mono", monospace;
276        font-size: 0.65rem;
277        font-weight: 600;
278        color: var(--accent);
279        background: transparent;
280        border: 1px solid var(--accent-border);
281        border-radius: 3px;
282        padding: 0.2rem 0.6rem;
283        margin-bottom: 1.25rem;
284        letter-spacing: 0.05em;
285        text-transform: uppercase;
286      }
287
288      .hero-tagline {
289        font-family: "Bricolage Grotesque", sans-serif;
290        font-size: 2.8rem;
291        font-weight: 800;
292        color: var(--text);
293        margin-bottom: 1rem;
294        letter-spacing: -0.03em;
295        line-height: 1.1;
296      }
297
298      .hero-tagline-accent {
299        background: linear-gradient(135deg, var(--accent), #fbbf24);
300        -webkit-background-clip: text;
301        -webkit-text-fill-color: transparent;
302        background-clip: text;
303        transition: opacity 0.6s ease;
304      }
305
306      .hero-cta {
307        display: inline-flex;
308        gap: 0.75rem;
309        margin-bottom: 0.5rem;
310      }
311
312      .btn {
313        display: inline-flex;
314        align-items: center;
315        padding: 0.55rem 1.25rem;
316        border-radius: 6px;
317        font-family: "IBM Plex Sans", sans-serif;
318        font-size: 0.85rem;
319        font-weight: 500;
320        text-decoration: none;
321        transition: all 0.15s;
322        border: 1px solid transparent;
323      }
324
325      .btn:hover {
326        text-decoration: none;
327      }
328
329      .btn-primary {
330        background: var(--accent);
331        color: #fff;
332      }
333
334      .btn-primary:hover {
335        background: var(--accent-dim);
336      }
337
338      .btn-ghost {
339        background: transparent;
340        color: var(--text-muted);
341        border-color: var(--border-light);
342      }
343
344      .btn-ghost:hover {
345        color: var(--text);
346        border-color: var(--text-dim);
347      }
348
349      /* ---- Steps (how it works) ---- */
350
351      .steps-list {
352        list-style: none;
353        padding: 0;
354        margin: 1rem 0 1.5rem;
355        counter-reset: step;
356      }
357
358      .steps-list li {
359        counter-increment: step;
360        display: flex;
361        gap: 1rem;
362        align-items: flex-start;
363        padding: 0.75rem 0;
364        border-bottom: 1px solid var(--border);
365        margin: 0;
366      }
367
368      .steps-list li:last-child {
369        border-bottom: none;
370      }
371
372      .steps-list li::before {
373        content: counter(step);
374        display: flex;
375        align-items: center;
376        justify-content: center;
377        width: 1.75rem;
378        height: 1.75rem;
379        border-radius: 50%;
380        background: var(--accent-bg);
381        border: 1px solid var(--accent-border);
382        color: var(--accent);
383        font-family: "Bricolage Grotesque", sans-serif;
384        font-size: 0.78rem;
385        font-weight: 700;
386        flex-shrink: 0;
387        margin-top: 0.1rem;
388      }
389
390      .step-body h4 {
391        font-size: 0.9rem;
392        font-weight: 600;
393        color: var(--text);
394        margin: 0 0 0.15rem;
395      }
396
397      .step-body p {
398        font-size: 0.85rem;
399        color: var(--text-muted);
400        margin: 0;
401      }
402
403      /* ---- State diagram ---- */
404
405      .state-flow {
406        display: flex;
407        align-items: flex-start;
408        gap: 0;
409        padding: 1.25rem 0;
410        overflow-x: auto;
411        margin: 0.5rem 0 0.75rem;
412      }
413
414      .sf-node {
415        display: flex;
416        flex-direction: column;
417        align-items: center;
418        gap: 0.25rem;
419        flex-shrink: 0;
420      }
421
422      .sf-box {
423        font-family: "IBM Plex Mono", monospace;
424        font-size: 0.78rem;
425        font-weight: 500;
426        padding: 0.45rem 0.85rem;
427        border-radius: 6px;
428        border: 1px solid var(--border);
429        background: var(--bg-card);
430        color: var(--text);
431        white-space: nowrap;
432        transition: border-color 0.15s;
433      }
434
435      .sf-box.sf-task {
436        border-color: rgba(249, 115, 22, 0.3);
437        background: rgba(249, 115, 22, 0.06);
438      }
439      .sf-box.sf-wait {
440        border-color: rgba(167, 139, 250, 0.3);
441        background: rgba(167, 139, 250, 0.06);
442      }
443      .sf-box.sf-done {
444        border-color: rgba(52, 211, 153, 0.3);
445        background: rgba(52, 211, 153, 0.06);
446      }
447
448      .sf-type {
449        font-family: "IBM Plex Mono", monospace;
450        font-size: 0.65rem;
451        color: var(--text-dim);
452      }
453
454      .sf-step {
455        display: flex;
456        align-items: flex-start;
457      }
458
459      .sf-arrow {
460        color: var(--text-dim);
461        font-size: 0.75rem;
462        padding: 0 0.35rem;
463        flex-shrink: 0;
464        user-select: none;
465        line-height: 1;
466        /* Match sf-box height: 0.78rem line + 0.45rem*2 padding + 2px border */
467        height: calc(0.78rem * 1.75 + 0.9rem + 2px);
468        display: flex;
469        align-items: center;
470      }
471
472      .state-note {
473        font-size: 0.82rem;
474        color: var(--text-dim);
475        margin-bottom: 1.5rem;
476      }
477
478      /* ---- Code block ---- */
479
480      .code-block {
481        background: var(--bg-inset);
482        border: 1px solid var(--border);
483        border-radius: 8px;
484        overflow: hidden;
485        margin: 1rem 0 1.5rem;
486      }
487
488      .code-header {
489        background: var(--bg-card);
490        border-bottom: 1px solid var(--border);
491        padding: 0.5rem 1rem;
492        display: flex;
493        align-items: center;
494        justify-content: space-between;
495      }
496
497      .code-filename {
498        font-family: "IBM Plex Mono", monospace;
499        font-size: 0.75rem;
500        color: var(--text-dim);
501      }
502
503      .code-block pre {
504        margin: 0;
505        padding: 1rem 1.25rem;
506        font-size: 0.8rem;
507        line-height: 1.75;
508        overflow-x: auto;
509        color: var(--text-muted);
510      }
511
512      .code-block .ck {
513        color: var(--accent);
514      }
515      .code-block .cv {
516        color: var(--text);
517      }
518      .code-block .cc {
519        color: var(--text-dim);
520        font-style: italic;
521      }
522      .code-block .cs {
523        color: var(--green);
524      }
525      .code-block .ca {
526        color: var(--violet);
527      }
528
529      /* ---- Example tabs ---- */
530
531      .example-tabs {
532        margin: 1rem 0 1.5rem;
533      }
534
535      .tab-bar {
536        display: flex;
537        gap: 0.35rem;
538        margin-bottom: 0.5rem;
539      }
540
541      .tab-btn {
542        background: transparent;
543        border: 1px solid var(--border);
544        border-radius: 4px;
545        color: var(--text-dim);
546        padding: 0.3rem 0.8rem;
547        font-family: "IBM Plex Mono", monospace;
548        font-size: 0.73rem;
549        cursor: pointer;
550        transition:
551          color 0.15s,
552          border-color 0.15s,
553          background 0.15s;
554      }
555
556      .tab-btn.active {
557        color: var(--accent);
558        border-color: var(--accent-border);
559        background: var(--accent-bg);
560      }
561
562      .tab-btn:hover:not(.active) {
563        color: var(--text-muted);
564        border-color: var(--border-light);
565      }
566
567      .example-tabs [data-panel="yaml"] .code-block {
568        margin: 0;
569      }
570
571      .diagram-panel {
572        background: var(--bg-inset);
573        border: 1px solid var(--border);
574        border-radius: 8px;
575        padding: 1.5rem 1rem;
576        overflow-x: auto;
577      }
578
579      .diagram-panel svg {
580        max-width: 100%;
581        height: auto;
582        display: block;
583        margin: 0 auto;
584      }
585
586      /* ---- Info cards ---- */
587
588      .info-grid {
589        display: grid;
590        grid-template-columns: repeat(2, 1fr);
591        gap: 0.75rem;
592        margin: 1rem 0 1.5rem;
593      }
594
595      .info-card {
596        background: var(--bg-card);
597        border: 1px solid var(--border);
598        border-radius: 8px;
599        padding: 1rem 1.15rem;
600      }
601
602      .info-card h4 {
603        font-size: 0.88rem;
604        font-weight: 600;
605        color: var(--text);
606        margin: 0 0 0.3rem;
607      }
608
609      .info-card p {
610        font-size: 0.8rem;
611        color: var(--text-muted);
612        line-height: 1.6;
613        margin: 0;
614      }
615
616      /* ---- CLI reference table ---- */
617
618      .cli-table {
619        width: 100%;
620        border-collapse: collapse;
621        margin: 1rem 0 1.5rem;
622        font-size: 0.85rem;
623      }
624
625      .cli-table th {
626        text-align: left;
627        padding: 0.6rem 1rem;
628        font-weight: 600;
629        color: var(--text-dim);
630        font-size: 0.72rem;
631        text-transform: uppercase;
632        letter-spacing: 0.06em;
633        border-bottom: 1px solid var(--border-light);
634        background: var(--bg-card);
635      }
636
637      .cli-table td {
638        padding: 0.6rem 1rem;
639        border-bottom: 1px solid var(--border);
640        color: var(--text-muted);
641      }
642
643      .cli-table td code {
644        background: var(--bg-code);
645        color: var(--cyan);
646        padding: 0.15rem 0.4rem;
647        border-radius: 3px;
648        font-size: 0.82rem;
649        border: 1px solid var(--border);
650      }
651
652      .cli-table tr:last-child td {
653        border-bottom: none;
654      }
655
656      /* ---- Install block ---- */
657
658      .install-block {
659        background: var(--bg-card);
660        border: 1px solid var(--border);
661        border-left: 3px solid var(--accent);
662        border-radius: 8px;
663        padding: 0.9rem 1.25rem;
664        position: relative;
665        display: flex;
666        align-items: center;
667        gap: 0.5rem;
668        margin: 1rem 0;
669        max-width: 520px;
670      }
671
672      .install-block .prompt-char {
673        color: var(--accent);
674        user-select: none;
675        font-family: "IBM Plex Mono", monospace;
676        font-weight: 500;
677        font-size: 0.88rem;
678      }
679
680      .install-block code {
681        font-size: 0.88rem;
682        color: var(--text);
683      }
684
685      .copy-btn {
686        position: absolute;
687        right: 0.75rem;
688        top: 50%;
689        transform: translateY(-50%);
690        background: var(--bg);
691        border: 1px solid var(--border);
692        color: var(--text-dim);
693        padding: 0.3rem 0.65rem;
694        border-radius: 4px;
695        font-family: "IBM Plex Mono", monospace;
696        font-size: 0.7rem;
697        cursor: pointer;
698        transition: all 0.15s;
699      }
700
701      .copy-btn:hover {
702        border-color: var(--accent);
703        color: var(--accent);
704        box-shadow: 0 0 8px rgba(249, 115, 22, 0.15);
705      }
706
707      .copy-btn.copied {
708        border-color: var(--green);
709        color: var(--green);
710      }
711
712      /* ---- Mobile sidebar toggle ---- */
713
714      .mobile-header {
715        display: none;
716        position: sticky;
717        top: 0;
718        z-index: 100;
719        background: var(--bg-sidebar);
720        border-bottom: 1px solid var(--border);
721        padding: 0.75rem 1rem;
722        align-items: center;
723        justify-content: space-between;
724      }
725
726      .mobile-header .logo-text {
727        font-family: "Bricolage Grotesque", sans-serif;
728        font-size: 1.1rem;
729        font-weight: 800;
730        color: var(--text);
731      }
732
733      .mobile-header .logo-text span {
734        color: var(--accent);
735      }
736
737      .menu-btn {
738        background: none;
739        border: 1px solid var(--border);
740        color: var(--text-muted);
741        padding: 0.3rem 0.6rem;
742        border-radius: 4px;
743        font-family: "IBM Plex Mono", monospace;
744        font-size: 0.75rem;
745        cursor: pointer;
746      }
747
748      /* ---- Responsive ---- */
749
750      @media (max-width: 860px) {
751        .sidebar {
752          position: fixed;
753          left: -16.25rem;
754          z-index: 200;
755          transition: left 0.25s ease;
756          box-shadow: 4px 0 20px rgba(0, 0, 0, 0.5);
757        }
758
759        .sidebar.open {
760          left: 0;
761        }
762
763        .sidebar-overlay {
764          display: none;
765          position: fixed;
766          inset: 0;
767          background: rgba(0, 0, 0, 0.5);
768          z-index: 199;
769        }
770
771        .sidebar-overlay.open {
772          display: block;
773        }
774
775        .mobile-header {
776          display: flex;
777        }
778
779        .main {
780          padding: 1.5rem 1.25rem 3rem;
781        }
782
783        .info-grid {
784          grid-template-columns: 1fr;
785        }
786
787        .info-card,
788        .action-ref {
789          overflow: hidden;
790          overflow-wrap: break-word;
791          word-break: break-word;
792          min-width: 0;
793        }
794
795        .install-block {
796          max-width: 100%;
797          flex-wrap: wrap;
798        }
799
800        .cli-table {
801          display: block;
802          overflow-x: auto;
803          -webkit-overflow-scrolling: touch;
804        }
805
806        .state-flow {
807          padding: 1rem 0;
808          flex-wrap: wrap;
809        }
810      }
811
812      /* ---- Sidebar sub-links (category TOC) ---- */
813
814      .sidebar-sublink {
815        display: block;
816        padding: 0.2rem 1.25rem 0.2rem 2.75rem;
817        font-size: 0.75rem;
818        font-family: "IBM Plex Mono", monospace;
819        color: var(--text-dim);
820        text-decoration: none;
821        transition: color 0.15s;
822        line-height: 1.5;
823      }
824
825      .sidebar-sublink:hover {
826        color: var(--text-muted);
827        text-decoration: none;
828      }
829
830      /* ---- Action reference ---- */
831
832      .action-ref {
833        background: var(--bg-card);
834        border: 1px solid var(--border);
835        border-radius: 8px;
836        padding: 1.25rem 1.5rem;
837        margin-bottom: 1rem;
838      }
839
840      .action-header {
841        display: flex;
842        align-items: center;
843        gap: 0.6rem;
844        margin-bottom: 0.5rem;
845      }
846
847      .action-title {
848        font-family: "IBM Plex Mono", monospace;
849        font-size: 0.95rem;
850        font-weight: 600;
851        color: var(--accent);
852        display: flex;
853        align-items: center;
854        gap: 0.5rem;
855      }
856
857      .action-title::before {
858        content: "";
859        display: inline-block;
860        width: 7px;
861        height: 7px;
862        border-radius: 50%;
863        background: var(--accent);
864        flex-shrink: 0;
865      }
866
867      .action-header:has(.badge-async) .action-title::before {
868        background: var(--violet);
869      }
870
871      .action-header:has(.badge-sync) .action-title::before {
872        background: var(--green);
873      }
874
875      .action-desc {
876        font-size: 0.88rem;
877        color: var(--text-muted);
878        margin-bottom: 0.75rem;
879        line-height: 1.6;
880      }
881
882      .badge {
883        display: inline-block;
884        font-family: "IBM Plex Mono", monospace;
885        font-size: 0.63rem;
886        font-weight: 500;
887        padding: 0.15rem 0.5rem;
888        border-radius: 100px;
889        flex-shrink: 0;
890      }
891
892      .badge-async {
893        background: rgba(167, 139, 250, 0.1);
894        border: 1px solid rgba(167, 139, 250, 0.25);
895        color: var(--violet);
896      }
897
898      .badge-sync {
899        background: rgba(52, 211, 153, 0.1);
900        border: 1px solid rgba(52, 211, 153, 0.25);
901        color: var(--green);
902      }
903
904      .param-section {
905        margin-top: 0.85rem;
906      }
907
908      .param-section-title {
909        font-size: 0.68rem;
910        font-weight: 600;
911        color: var(--text-dim);
912        text-transform: uppercase;
913        letter-spacing: 0.07em;
914        margin-bottom: 0.4rem;
915      }
916
917      .param-table {
918        width: 100%;
919        border-collapse: collapse;
920        font-size: 0.82rem;
921        border-radius: 6px;
922        overflow: hidden;
923        border: 1px solid var(--border);
924      }
925
926      .param-table th {
927        text-align: left;
928        padding: 0.4rem 0.75rem;
929        font-size: 0.66rem;
930        font-weight: 600;
931        color: var(--text-dim);
932        text-transform: uppercase;
933        letter-spacing: 0.07em;
934        background: var(--bg-inset);
935        border-bottom: 1px solid var(--border-light);
936      }
937
938      .param-table td {
939        padding: 0.45rem 0.75rem;
940        border-bottom: 1px solid var(--border);
941        color: var(--text-muted);
942        vertical-align: top;
943      }
944
945      .param-table td:first-child {
946        font-family: "IBM Plex Mono", monospace;
947        color: var(--cyan);
948        font-size: 0.8rem;
949        white-space: nowrap;
950      }
951
952      .param-table td:nth-child(2) {
953        font-family: "IBM Plex Mono", monospace;
954        color: var(--text-dim);
955        font-size: 0.78rem;
956        white-space: nowrap;
957      }
958
959      .param-table tr:last-child td {
960        border-bottom: none;
961      }
962
963      .param-none {
964        font-size: 0.82rem;
965        color: var(--text-dim);
966        margin-top: 0.35rem;
967      }
968
969      @media (max-width: 480px) {
970        .hero-tagline {
971          font-size: 1.8rem;
972        }
973
974        .hero-cta {
975          flex-direction: column;
976        }
977
978        .btn {
979          width: 100%;
980          justify-content: center;
981          max-width: 280px;
982        }
983
984        .cli-table {
985          font-size: 0.78rem;
986        }
987
988        .cli-table th,
989        .cli-table td {
990          padding: 0.5rem 0.6rem;
991        }
992
993        .code-block pre {
994          font-size: 0.72rem;
995          padding: 0.75rem 1rem;
996        }
997
998        .action-ref {
999          padding: 1rem;
1000        }
1001
1002        .action-title {
1003          font-size: 0.85rem;
1004        }
1005
1006        .action-desc {
1007          font-size: 0.82rem;
1008        }
1009      }
1010
1011      /* ---- Scrollable param-table on narrow phones ---- */
1012      @media (max-width: 560px) {
1013        .param-section {
1014          overflow-x: auto;
1015          -webkit-overflow-scrolling: touch;
1016          margin-left: -0.25rem;
1017          margin-right: -0.25rem;
1018        }
1019
1020        .param-table {
1021          font-size: 0.75rem;
1022          width: max-content;
1023          min-width: 100%;
1024        }
1025
1026        .param-table th {
1027          white-space: nowrap;
1028        }
1029
1030        .param-table th,
1031        .param-table td {
1032          padding: 0.35rem 0.5rem;
1033        }
1034
1035        .param-table td:first-child {
1036          font-size: 0.73rem;
1037        }
1038
1039        .param-table td:nth-child(2) {
1040          font-size: 0.7rem;
1041        }
1042
1043        .install-block {
1044          gap: 0.35rem;
1045        }
1046
1047        .install-block code {
1048          font-size: 0.78rem;
1049        }
1050
1051        .copy-btn {
1052          position: static;
1053          transform: none;
1054          flex-shrink: 0;
1055          padding: 0.25rem 0.5rem;
1056          font-size: 0.65rem;
1057        }
1058      }
1059    </style>
1060  </head>
1061  <body>
1062    <div class="mobile-header">
1063      <span class="logo-text">erg<span>.</span></span>
1064      <button class="menu-btn" onclick="toggleSidebar()">menu</button>
1065    </div>
1066
1067    <div
1068      class="sidebar-overlay"
1069      id="sidebarOverlay"
1070      onclick="toggleSidebar()"
1071    ></div>
1072
1073    <div class="page">
1074      <nav class="sidebar" id="sidebar"></nav>
1075      
1075<script src="sidebar.js"></script>
1075
1076
1077      <!-- Content -->
1078      <main class="main">
1079        <!-- Overview -->
1080        <section id="overview">
1081          <span class="hero-badge">agent orchestrator</span>
1082          <p class="hero-tagline">
1083            erg <span class="hero-tagline-accent" id="rotating-tagline">follows your workflow.</span>
1084          </p>
1085          <p>
1086            Autonomous orchestrator for Claude Code. Polls GitHub, Asana, or
1087            Linear for issues, starts containerized Claude sessions, and drives
1088            the full PR lifecycle &mdash; as automated as your workflow allows.
1089          </p>
1090          <div class="hero-cta">
1091            <a href="#install" class="btn btn-primary">install</a>
1092            <a href="https://github.com/zhubert/erg" class="btn btn-ghost"
1093              >view on github</a
1094            >
1095          </div>
1096        </section>
1097
1098        <!-- How it works -->
1099        <h2 id="how-it-works">How it works</h2>
1100        <p>
1101          At its core, erg is a
1102          <strong>state machine engine paired with AI coding</strong>. Each
1103          issue becomes a work item that advances through a configurable
1104          flowchart of states — from AI-generated code to a merged PR. You
1105          define exactly how much automation applies: require human review,
1106          auto-merge after CI, loop back for fixes, or notify external systems
1107          at any step.
1108        </p>
1109        <ol class="steps-list">
1110          <li>
1111            <div class="step-body">
1112              <h4>Tag or label an issue</h4>
1113              <p>
1114                Mark a task in GitHub, Asana, or Linear with the configured
1115                trigger label (e.g. <code>ai-assisted</code>).
1116              </p>
1117            </div>
1118          </li>
1119          <li>
1120            <div class="step-body">
1121              <h4>Orchestrator picks it up</h4>
1122              <p>
1123                erg starts a containerized Claude session. With planning
1124                enabled, no branch is created yet — Claude reads the codebase in
1125                read-only mode.
1126              </p>
1127            </div>
1128          </li>
1129          <li>
1130            <div class="step-body">
1131              <h4>Claude analyzes and posts a plan</h4>
1132              <p>
1133                The <code>ai.plan</code> session explores the codebase and posts
1134                a structured implementation plan as an issue comment — no code
1135                written yet.
1136              </p>
1137            </div>
1138          </li>
1139          <li>
1140            <div class="step-body">
1141              <h4>You review and approve</h4>
1142              <p>
1143                Reply with approval (e.g. "LGTM") to proceed, or leave feedback.
1144                Claude revises the plan and loops back until you approve.
1145              </p>
1146            </div>
1147          </li>
1148          <li>
1149            <div class="step-body">
1150              <h4>Claude writes the code</h4>
1151              <p>
1152                Once approved, <code>ai.code</code> creates a branch, implements
1153                the changes, runs tests, and commits.
1154              </p>
1155            </div>
1156          </li>
1157          <li>
1158            <div class="step-body">
1159              <h4>State machine advances</h4>
1160              <p>
1161                The workflow engine opens a PR, waits for CI, handles review
1162                feedback, and merges — automatically, according to your rules.
1163              </p>
1164            </div>
1165          </li>
1166        </ol>
1167
1168        <!-- Installation -->
1169        <h2 id="install">Installation</h2>
1170        <div class="install-block">
1171          <span class="prompt-char">$</span>
1172          <code>brew install zhubert/tap/erg</code>
1173          <button
1174            class="copy-btn"
1175            onclick="copyCmd(this, 'brew install zhubert/tap/erg')"
1176          >
1177            copy
1178          </button>
1179        </div>
1180        <p style="font-size: 0.85rem; color: var(--text-dim); margin-top: 0.75rem;">
1181          Or build from source: <code>go build -o erg .</code>
1182        </p>
1183        <p style="font-size: 0.85rem; color: var(--text-dim); margin-top: 0.5rem;">
1184          <strong>Prerequisite:</strong> a container runtime must be installed and running.
1185          Supported options:
1186          <a href="https://orbstack.dev">OrbStack</a> (recommended on macOS),
1187          <a href="https://docs.docker.com/get-docker/">Docker Desktop</a>, or
1188          <a href="https://github.com/abiosoft/colima">Colima</a>.
1189        </p>
1190
1191        <h3 id="quickstart">Quick start</h3>
1192        <ol class="steps-list">
1193          <li>
1194            <div class="step-body">
1195              <h4>Configure erg</h4>
1196              <p>
1197                Run <code>erg configure</code> inside your repo. It will ask which
1198                issue tracker you use (GitHub, Asana, or Linear), walk through
1199                credentials, and scaffold a default workflow file.
1200              </p>
1201              <div class="install-block" style="margin-top: 0.75rem; max-width: 100%;">
1202                <span class="prompt-char">$</span>
1203                <code>erg configure</code>
1204                <button class="copy-btn" onclick="copyCmd(this, 'erg configure')">copy</button>
1205              </div>
1206            </div>
1207          </li>
1208          <li>
1209            <div class="step-body">
1210              <h4>Confirm your container runtime is running</h4>
1211              <p>
1212                OrbStack, Docker Desktop, or Colima must be up before erg can
1213                launch sessions. Verify with <code>docker ps</code>.
1214              </p>
1215            </div>
1216          </li>
1217          <li>
1218            <div class="step-body">
1219              <h4>Start the daemon</h4>
1220              <p>
1221                Start erg with <code>brew services start erg</code>, then check
1222                it's healthy: <code>erg status</code>. If something looks off,
1223                tail the log: <code>tail -f ~/.erg/logs/erg.log</code>.
1224              </p>
1225              <div class="install-block" style="margin-top: 0.75rem; max-width: 100%;">
1226                <span class="prompt-char">$</span>
1227                <code>brew services start erg</code>
1228                <button class="copy-btn" onclick="copyCmd(this, 'brew services start erg')">copy</button>
1229              </div>
1230            </div>
1231          </li>
1232          <li>
1233            <div class="step-body">
1234              <h4>Label your first issue</h4>
1235              <p>
1236                Open an issue in your configured tracker and apply the trigger
1237                label (e.g. <code>ai-assisted</code>). erg will pick it up within the
1238                next poll interval.
1239              </p>
1240            </div>
1241          </li>
1242          <li>
1243            <div class="step-body">
1244              <h4>Watch it go</h4>
1245              <p>
1246                Open <code>http://localhost:21122</code> in your browser. You'll
1247                see the session appear and progress in real time.
1248              </p>
1249            </div>
1250          </li>
1251        </ol>
1252
1253        <!-- ============ LIVE DASHBOARD SIMULATION ============ -->
1254        <div class="sim-wrap" style="margin: 2rem 0 2.5rem;">
1255          <div class="sim-label">live dashboard preview</div>
1256          <div class="sim-header">
1257            <div class="sim-header-left">
1258              <h3><span>erg</span> dashboard</h3>
1259            </div>
1260            <div class="sim-conn">
1261              <div class="sim-conn-dot"></div>
1262              <span>connected</span>
1263            </div>
1264          </div>
1265          <div class="sim-body">
1266            <div class="sim-summary" id="simSummary"></div>
1267            <div id="simContent"></div>
1268          </div>
1269        </div>
1270        <p style="font-size: 0.82rem; color: var(--text-dim); text-align: center; margin-top: -1.5rem; margin-bottom: 2rem;">
1271          Monitor all your agents in real time. <a href="dashboard.html#dashboard">Learn more &rarr;</a>
1272        </p>
1273        <!-- ============ END SIMULATION ============ -->
1274
1275        <div
1276          style="
1277            margin-top: 3rem;
1278            padding-top: 1.5rem;
1279            border-top: 1px solid transparent;
1280            border-image: linear-gradient(
1281                90deg,
1282                transparent,
1283                var(--border-light),
1284                transparent
1285              )
1286              1;
1287            font-size: 0.8rem;
1288            color: var(--text-dim);
1289            text-align: center;
1290          "
1291        >
1292          made by
1293          <a href="https://www.zhubert.com" style="color: var(--accent)"
1294            >zack</a
1295          >
1296          &middot; mit license
1297        </div>
1298      </main>
1299    </div>
1300
1301    
1301<script>
1302      function switchTab(btn, tab) {
1303        var tabs = btn.closest(".example-tabs");
1304        tabs.querySelectorAll(".tab-btn").forEach(function (b) {
1305          b.classList.remove("active");
1306        });
1307        btn.classList.add("active");
1308        tabs.querySelectorAll("[data-panel]").forEach(function (p) {
1309          p.style.display = "none";
1310        });
1311        var panel = tabs.querySelector('[data-panel="' + tab + '"]');
1312        if (panel) panel.style.display = "";
1313      }
1314
1315      function copyCmd(btn, cmd) {
1316        navigator.clipboard.writeText(cmd).then(function () {
1317          btn.textContent = "copied";
1318          btn.classList.add("copied");
1319          setTimeout(function () {
1320            btn.textContent = "copy";
1321            btn.classList.remove("copied");
1322          }, 2000);
1323        });
1324      }
1325
1326      // Label param-table cells for responsive stacking
1327      document.querySelectorAll(".param-table").forEach(function (table) {
1328        var headers = Array.from(table.querySelectorAll("thead th")).map(
1329          function (th) {
1330            return th.textContent.trim();
1331          },
1332        );
1333        table.querySelectorAll("tbody tr").forEach(function (row) {
1334          row.querySelectorAll("td").forEach(function (td, i) {
1335            if (headers[i]) td.setAttribute("data-label", headers[i]);
1336          });
1337        });
1338      });
1339    </script>
1339
1340    
1340<script src="sim-dashboard.js"></script>
1340
1341    
1341<script>
1342      (function () {
1343        var taglines = [
1344          "follows your workflow.",
1345          "automates from issue to PR.",
1346          "is your AI coworker.",
1347          "collaborates from plan to review."
1348        ];
1349        var el = document.getElementById("rotating-tagline");
1350        if (!el) return;
1351        var idx = 0;
1352        setInterval(function () {
1353          el.style.opacity = "0";
1354          setTimeout(function () {
1355            idx = (idx + 1) % taglines.length;
1356            el.textContent = taglines[idx];
1357            el.style.opacity = "1";
1358          }, 600);
1359        }, 8000);
1360      })();
1361    </script>
1361
1362  </body>
1363</html>
1364

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.