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 — 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 →</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 · 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.