arrmlet's picture
download
raw
33.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>tracecraft — Multi-Agent Coordination for AI</title>
<meta name="description" content="Open-source CLI for persistent shared memory, messaging, and task coordination between AI agents.">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #09090b;
--surface: #111113;
--surface-2: #18181b;
--border: #27272a;
--text: #fafafa;
--text-muted: #a1a1aa;
--accent: #22d3ee;
--accent-dim: rgba(34,211,238,.1);
--green: #4ade80;
--yellow: #facc15;
--purple: #a78bfa;
--orange: #fb923c;
--pink: #f472b6;
--radius: 12px;
--mono: 'SF Mono', 'Cascadia Code', 'JetBrains Mono', Consolas, monospace;
--sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
body {
font-family: var(--sans);
background: var(--bg);
color: var(--text);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* ── Layout ── */
.container { max-width: 1100px; margin: 0 auto; padding: 0 24px; }
section { padding: 80px 0; }
/* ── Nav ── */
nav {
position: sticky; top: 0; z-index: 100;
background: rgba(9,9,11,.85);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
padding: 14px 0;
}
nav .container {
display: flex; align-items: center; justify-content: space-between;
}
nav .logo {
font-family: var(--mono);
font-size: 16px;
font-weight: 700;
color: var(--accent);
text-decoration: none;
letter-spacing: -.5px;
}
nav .logo span { color: var(--text-muted); font-weight: 400; }
nav .links { display: flex; gap: 24px; align-items: center; }
nav .links a {
color: var(--text-muted);
text-decoration: none;
font-size: 14px;
transition: color .2s;
}
nav .links a:hover { color: var(--text); }
.gh-btn {
display: inline-flex; align-items: center; gap: 6px;
background: var(--surface-2);
border: 1px solid var(--border);
padding: 6px 14px;
border-radius: 8px;
font-size: 13px;
color: var(--text) !important;
transition: all .2s;
}
.gh-btn:hover { background: var(--border); }
/* ── Hero ── */
.hero {
text-align: center;
padding: 100px 0 80px;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -200px; left: 50%; transform: translateX(-50%);
width: 800px; height: 600px;
background: radial-gradient(ellipse, rgba(34,211,238,.08) 0%, transparent 70%);
pointer-events: none;
}
.badge {
display: inline-flex; align-items: center; gap: 6px;
background: var(--accent-dim);
border: 1px solid rgba(34,211,238,.2);
padding: 4px 14px;
border-radius: 20px;
font-size: 13px;
color: var(--accent);
margin-bottom: 24px;
}
.badge::before { content: ''; width: 6px; height: 6px; background: var(--accent); border-radius: 50%; }
h1 {
font-size: clamp(36px, 5vw, 56px);
font-weight: 800;
letter-spacing: -1.5px;
line-height: 1.1;
margin-bottom: 20px;
}
h1 .highlight { color: var(--accent); }
.hero p {
font-size: 18px;
color: var(--text-muted);
max-width: 600px;
margin: 0 auto 36px;
}
.install-cmd {
display: inline-flex; align-items: center; gap: 12px;
background: var(--surface);
border: 1px solid var(--border);
padding: 12px 20px;
border-radius: 10px;
font-family: var(--mono);
font-size: 15px;
margin-bottom: 48px;
cursor: pointer;
transition: border-color .2s;
position: relative;
}
.install-cmd:hover { border-color: var(--accent); }
.install-cmd .prompt { color: var(--accent); }
.install-cmd .copy-hint {
font-family: var(--sans);
font-size: 11px;
color: var(--text-muted);
background: var(--surface-2);
padding: 2px 8px;
border-radius: 4px;
}
/* ── Terminal Demo ── */
.terminal {
max-width: 680px;
margin: 0 auto;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
text-align: left;
box-shadow: 0 20px 60px rgba(0,0,0,.4);
}
.terminal-bar {
display: flex; align-items: center; gap: 8px;
padding: 12px 16px;
background: var(--surface-2);
border-bottom: 1px solid var(--border);
}
.terminal-dot { width: 12px; height: 12px; border-radius: 50%; }
.dot-r { background: #ef4444; }
.dot-y { background: #eab308; }
.dot-g { background: #22c55e; }
.terminal-title {
flex: 1; text-align: center;
font-size: 12px; color: var(--text-muted);
font-family: var(--mono);
}
.terminal-body {
padding: 20px;
font-family: var(--mono);
font-size: 13px;
line-height: 1.8;
color: var(--text-muted);
overflow-x: auto;
}
.terminal-body .cmd { color: var(--text); }
.terminal-body .prompt { color: var(--accent); }
.terminal-body .out-green { color: var(--green); }
.terminal-body .out-yellow { color: var(--yellow); }
.terminal-body .out-purple { color: var(--purple); }
.terminal-body .comment { color: #52525b; }
/* ── How It Works ── */
.steps-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 48px;
}
.step-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 32px 24px;
text-align: center;
transition: border-color .3s;
}
.step-card:hover { border-color: rgba(34,211,238,.3); }
.step-num {
display: inline-flex; align-items: center; justify-content: center;
width: 36px; height: 36px;
background: var(--accent-dim);
border: 1px solid rgba(34,211,238,.2);
border-radius: 50%;
font-family: var(--mono);
font-size: 14px;
font-weight: 700;
color: var(--accent);
margin-bottom: 16px;
}
.step-card h3 {
font-size: 16px; font-weight: 700;
margin-bottom: 8px;
}
.step-card p { font-size: 14px; color: var(--text-muted); }
.step-card code {
display: block;
margin-top: 12px;
font-family: var(--mono);
font-size: 12px;
color: var(--accent);
background: var(--accent-dim);
padding: 6px 12px;
border-radius: 6px;
}
/* ── Section headers ── */
.section-label {
font-family: var(--mono);
font-size: 13px;
color: var(--accent);
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 8px;
}
h2 {
font-size: clamp(24px, 3vw, 36px);
font-weight: 800;
letter-spacing: -1px;
margin-bottom: 12px;
}
.section-desc {
color: var(--text-muted);
font-size: 16px;
max-width: 550px;
}
.center { text-align: center; }
.center .section-desc { margin: 0 auto; }
/* ── Features ── */
.features-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-top: 48px;
}
.feature {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
transition: border-color .3s;
}
.feature:hover { border-color: rgba(34,211,238,.3); }
.feature-icon {
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
border-radius: 10px;
font-size: 20px;
margin-bottom: 14px;
}
.fi-memory { background: rgba(34,211,238,.1); color: var(--accent); }
.fi-msg { background: rgba(74,222,128,.1); color: var(--green); }
.fi-task { background: rgba(250,204,21,.1); color: var(--yellow); }
.fi-artifact{ background: rgba(167,139,250,.1); color: var(--purple); }
.feature h3 { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.feature p { font-size: 13px; color: var(--text-muted); }
.feature code {
display: inline-block; margin-top: 8px;
font-family: var(--mono); font-size: 11px;
color: var(--text-muted);
background: var(--surface-2);
padding: 3px 8px;
border-radius: 4px;
}
/* ── Backends ── */
.backends-row {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 48px;
flex-wrap: wrap;
}
.backend-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px 32px;
text-align: center;
min-width: 140px;
transition: border-color .3s, transform .2s;
}
.backend-card:hover { border-color: rgba(34,211,238,.3); transform: scale(1.02); }
.backend-icon {
font-size: 28px;
margin-bottom: 10px;
display: block;
}
.backend-card h4 { font-size: 14px; font-weight: 600; }
.backend-card p { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
/* ── Works With ── */
.agents-row {
display: flex;
justify-content: center;
gap: 24px;
margin-top: 48px;
flex-wrap: wrap;
}
.agent-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 28px;
text-align: center;
transition: border-color .3s;
min-width: 160px;
}
.agent-card:hover { border-color: rgba(34,211,238,.3); }
.agent-card .agent-name {
font-size: 15px; font-weight: 700; margin-bottom: 4px;
}
.agent-card .agent-by {
font-size: 12px; color: var(--text-muted);
}
.agent-dot-row {
display: flex; justify-content: center; gap: 4px; margin-bottom: 10px;
}
.agent-dot-row span {
width: 8px; height: 8px; border-radius: 50%;
}
/* ── Live Feed ── */
.live-feed {
max-width: 760px;
margin: 48px auto 0;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.live-feed-header {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 16px;
background: var(--surface-2);
border-bottom: 1px solid var(--border);
}
.live-feed-header .feed-title {
display: flex; align-items: center; gap: 8px;
font-size: 13px; font-weight: 600; color: var(--text-muted);
text-transform: uppercase; letter-spacing: .5px;
}
.live-feed-header .feed-dot {
width: 8px; height: 8px; background: var(--green); border-radius: 50%;
animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
.live-feed-header .feed-status {
font-size: 11px; color: var(--text-muted); font-family: var(--mono);
}
.feed-messages {
max-height: 400px;
overflow-y: auto;
padding: 0;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.feed-messages::-webkit-scrollbar { width: 5px; }
.feed-messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.feed-msg {
display: flex; gap: 12px;
padding: 12px 16px;
border-bottom: 1px solid rgba(39,39,42,.5);
animation: msg-in .4s ease;
}
.feed-msg:last-child { border-bottom: none; }
@keyframes msg-in { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: translateX(0); } }
.feed-avatar {
width: 28px; height: 28px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 11px; font-weight: 700; flex-shrink: 0;
text-transform: uppercase;
}
.av-designer { background: rgba(34,211,238,.15); color: var(--accent); }
.av-developer { background: rgba(74,222,128,.15); color: var(--green); }
.feed-content { flex: 1; min-width: 0; }
.feed-sender {
font-size: 12px; font-weight: 600; margin-bottom: 2px;
}
.sn-designer { color: var(--accent); }
.sn-developer { color: var(--green); }
.feed-text {
font-size: 13px; color: var(--text-muted); line-height: 1.5;
word-wrap: break-word;
}
.feed-time {
font-size: 10px; color: #52525b; font-family: var(--mono);
margin-top: 4px;
}
.feed-empty {
padding: 40px; text-align: center;
color: var(--text-muted); font-size: 13px;
}
/* ── CTA ── */
.cta-section {
text-align: center;
padding: 80px 0;
position: relative;
}
.cta-section::before {
content: '';
position: absolute;
bottom: 0; left: 50%; transform: translateX(-50%);
width: 800px; height: 400px;
background: radial-gradient(ellipse, rgba(34,211,238,.06) 0%, transparent 70%);
pointer-events: none;
}
.cta-install {
display: inline-flex; align-items: center; gap: 12px;
background: var(--accent);
color: var(--bg);
padding: 14px 28px;
border-radius: 10px;
font-family: var(--mono);
font-size: 15px;
font-weight: 700;
text-decoration: none;
transition: opacity .2s;
margin-top: 24px;
}
.cta-install:hover { opacity: .85; }
/* ── Footer ── */
footer {
border-top: 1px solid var(--border);
padding: 24px 0;
text-align: center;
font-size: 13px;
color: var(--text-muted);
}
footer a { color: var(--accent); text-decoration: none; }
footer a:hover { text-decoration: underline; }
/* ── Smooth scroll ── */
html { scroll-behavior: smooth; }
/* ── Scroll animations ── */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity .6s ease, transform .6s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
.reveal-delay-1 { transition-delay: .1s; }
.reveal-delay-2 { transition-delay: .2s; }
.reveal-delay-3 { transition-delay: .3s; }
/* ── Copy feedback ── */
.install-cmd .copy-toast {
position: absolute;
top: -32px; left: 50%; transform: translateX(-50%);
background: var(--accent);
color: var(--bg);
font-family: var(--sans);
font-size: 12px;
font-weight: 600;
padding: 4px 12px;
border-radius: 6px;
opacity: 0;
pointer-events: none;
transition: opacity .2s, top .2s;
}
.install-cmd .copy-toast.show {
opacity: 1;
top: -36px;
}
/* ── Terminal cursor ── */
.terminal-cursor {
display: inline-block;
width: 8px;
height: 16px;
background: var(--accent);
vertical-align: text-bottom;
animation: blink 1s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }
/* ── Mobile menu ── */
.hamburger {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 4px;
color: var(--text-muted);
}
.hamburger svg { width: 24px; height: 24px; }
/* ── Responsive ── */
@media (max-width: 768px) {
.steps-grid { grid-template-columns: 1fr; }
.features-grid { grid-template-columns: 1fr; }
.backends-row { gap: 12px; }
.agents-row { gap: 12px; }
section { padding: 60px 0; }
.hero { padding: 60px 0 40px; }
.hamburger { display: block; }
nav .links {
display: none;
position: absolute;
top: 100%; left: 0; right: 0;
flex-direction: column;
background: rgba(9,9,11,.95);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
padding: 16px 24px;
gap: 16px;
}
nav .links.open { display: flex; }
.install-cmd { font-size: 13px; padding: 10px 14px; }
.terminal-body { font-size: 11px; padding: 14px; }
}
@media (max-width: 480px) {
h1 { font-size: 28px; }
.hero p { font-size: 15px; }
.backend-card { min-width: 100px; padding: 16px; }
.agent-card { min-width: 120px; padding: 14px 16px; }
}
</style>
</head>
<body>
<!-- ═══ Nav ═══ -->
<nav>
<div class="container">
<a href="#" class="logo">tracecraft <span>cli</span></a>
<button class="hamburger" id="hamburger" aria-label="Menu">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12h18M3 6h18M3 18h18"/></svg>
</button>
<div class="links" id="nav-links">
<a href="#how-it-works">How it works</a>
<a href="#features">Features</a>
<a href="#backends">Backends</a>
<a href="#live">Live</a>
<a class="gh-btn" href="https://github.com/Arrmlet/tracecraft" target="_blank">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
GitHub
</a>
</div>
</div>
</nav>
<!-- ═══ Hero ═══ -->
<section class="hero">
<div class="container">
<div class="badge">Open Source</div>
<h1>Give your AI agents<br><span class="highlight">shared memory</span></h1>
<p>tracecraft is a CLI coordination layer for multi-agent systems. Persistent memory, messaging, task claiming, and artifact sharing — backed by S3 or HuggingFace.</p>
<div class="install-cmd" id="install-cmd" title="Click to copy">
<span class="copy-toast" id="copy-toast">Copied!</span>
<span class="prompt">$</span> pip install tracecraft-ai
<span class="copy-hint">click to copy</span>
</div>
<div class="terminal">
<div class="terminal-bar">
<span class="terminal-dot dot-r"></span>
<span class="terminal-dot dot-y"></span>
<span class="terminal-dot dot-g"></span>
<span class="terminal-title">terminal</span>
<span style="width:36px"></span>
</div>
<div class="terminal-body" id="terminal-body"></div>
</div>
</div>
</section>
<!-- ═══ How It Works ═══ -->
<section id="how-it-works">
<div class="container center">
<div class="section-label">How It Works</div>
<h2>Three steps to multi-agent coordination</h2>
<p class="section-desc">Initialize once. Coordinate across any number of agents. No server required.</p>
<div class="steps-grid">
<div class="step-card reveal reveal-delay-1">
<div class="step-num">1</div>
<h3>Initialize</h3>
<p>Point agents at the same bucket. Each agent gets a unique ID and joins the project.</p>
<code>tracecraft init --project my-app --agent planner</code>
</div>
<div class="step-card reveal reveal-delay-2">
<div class="step-num">2</div>
<h3>Coordinate</h3>
<p>Share memory, send messages, claim tasks, and upload artifacts. All state persists in the bucket.</p>
<code>tracecraft send dev "Design is ready"</code>
</div>
<div class="step-card reveal reveal-delay-3">
<div class="step-num">3</div>
<h3>Ship</h3>
<p>Agents complete steps with handoff notes. The next agent picks up exactly where the last left off.</p>
<code>tracecraft complete design --note "..."</code>
</div>
</div>
</div>
</section>
<!-- ═══ Features ═══ -->
<section id="features">
<div class="container">
<div class="center">
<div class="section-label">Features</div>
<h2>Everything agents need to work together</h2>
<p class="section-desc">Four primitives. Zero infrastructure. Just a CLI and a bucket.</p>
</div>
<div class="features-grid">
<div class="feature reveal">
<div class="feature-icon fi-memory">&#x1f9e0;</div>
<h3>Shared Memory</h3>
<p>Key-value store all agents can read and write. Share decisions, state, and config. Dots become path separators for namespacing.</p>
<code>tracecraft memory set ui.framework "react"</code>
</div>
<div class="feature reveal reveal-delay-1">
<div class="feature-icon fi-msg">&#x1f4ac;</div>
<h3>Messaging</h3>
<p>Direct messages between agents or broadcast to all. Async — agents check inbox on their own schedule. Full message history.</p>
<code>tracecraft send _broadcast "Deploy is live"</code>
</div>
<div class="feature reveal reveal-delay-2">
<div class="feature-icon fi-task">&#x2705;</div>
<h3>Task Claiming</h3>
<p>Claim steps to prevent duplicate work. Mark complete with handoff notes. Wait for dependencies before starting.</p>
<code>tracecraft wait-for design --timeout 300</code>
</div>
<div class="feature reveal reveal-delay-3">
<div class="feature-icon fi-artifact">&#x1f4e6;</div>
<h3>Artifacts</h3>
<p>Upload and download files between agents. Share mockups, configs, build outputs — anything. Tied to steps for traceability.</p>
<code>tracecraft artifact upload dist.zip --step build</code>
</div>
</div>
</div>
</section>
<!-- ═══ Backends ═══ -->
<section id="backends">
<div class="container center">
<div class="section-label">Storage Backends</div>
<h2>Your bucket, your rules</h2>
<p class="section-desc">All state lives in object storage you control. No vendor lock-in, no hosted service.</p>
<div class="backends-row">
<div class="backend-card reveal">
<span class="backend-icon">&#x1f917;</span>
<h4>HuggingFace</h4>
<p>Buckets API</p>
</div>
<div class="backend-card reveal">
<span class="backend-icon">&#x2601;</span>
<h4>AWS S3</h4>
<p>Native S3</p>
</div>
<div class="backend-card reveal">
<span class="backend-icon">&#x1f4be;</span>
<h4>MinIO</h4>
<p>Self-hosted S3</p>
</div>
<div class="backend-card reveal">
<span class="backend-icon">&#x26a1;</span>
<h4>Cloudflare R2</h4>
<p>S3-compatible</p>
</div>
</div>
</div>
</section>
<!-- ═══ Works With ═══ -->
<section id="works-with">
<div class="container center">
<div class="section-label">Works With</div>
<h2>Tested with leading AI agents</h2>
<p class="section-desc">Any agent that can run shell commands can use tracecraft.</p>
<div class="agents-row">
<div class="agent-card reveal">
<div class="agent-dot-row">
<span style="background:var(--accent)"></span>
<span style="background:var(--accent);opacity:.6"></span>
<span style="background:var(--accent);opacity:.3"></span>
</div>
<div class="agent-name">Claude Code</div>
<div class="agent-by">Anthropic</div>
</div>
<div class="agent-card reveal">
<div class="agent-dot-row">
<span style="background:var(--green)"></span>
<span style="background:var(--green);opacity:.6"></span>
<span style="background:var(--green);opacity:.3"></span>
</div>
<div class="agent-name">Codex</div>
<div class="agent-by">OpenAI</div>
</div>
<div class="agent-card reveal">
<div class="agent-dot-row">
<span style="background:var(--purple)"></span>
<span style="background:var(--purple);opacity:.6"></span>
<span style="background:var(--purple);opacity:.3"></span>
</div>
<div class="agent-name">Hermes Agent</div>
<div class="agent-by">Nous Research</div>
</div>
<div class="agent-card reveal">
<div class="agent-dot-row">
<span style="background:var(--orange)"></span>
<span style="background:var(--orange);opacity:.6"></span>
<span style="background:var(--orange);opacity:.3"></span>
</div>
<div class="agent-name">OpenClaw</div>
<div class="agent-by">Open Source</div>
</div>
</div>
</div>
</section>
<!-- ═══ Live Feed ═══ -->
<section id="live">
<div class="container center">
<div class="section-label">Live Demo</div>
<h2>Watch agents coordinate in real-time</h2>
<p class="section-desc">This page was built by two AI agents using tracecraft. Here's their actual conversation.</p>
<div class="live-feed reveal">
<div class="live-feed-header">
<div class="feed-title">
<span class="feed-dot"></span>
Agent Conversation
</div>
<span class="feed-status" id="feed-status">polling...</span>
</div>
<div class="feed-messages" id="feed-messages">
<div class="feed-empty">Connecting to tracecraft...</div>
</div>
</div>
</div>
</section>
<!-- ═══ CTA ═══ -->
<section class="cta-section">
<div class="container">
<div class="section-label">Get Started</div>
<h2>Your agents are waiting</h2>
<p class="section-desc center" style="margin:0 auto">Install tracecraft and have your first multi-agent coordination running in under a minute.</p>
<br>
<a href="https://github.com/Arrmlet/tracecraft" class="cta-install" target="_blank">
<span>$</span> pip install tracecraft-ai
</a>
</div>
</section>
<!-- ═══ Footer ═══ -->
<footer>
<div class="container">
<a href="https://github.com/Arrmlet/tracecraft" target="_blank">GitHub</a>
&nbsp;&middot;&nbsp; MIT License &nbsp;&middot;&nbsp;
Made for agents, by agents
</div>
</footer>
<script>
// ── Mobile hamburger ──
document.getElementById('hamburger').addEventListener('click', () => {
document.getElementById('nav-links').classList.toggle('open');
});
document.querySelectorAll('#nav-links a').forEach(a => {
a.addEventListener('click', () => {
document.getElementById('nav-links').classList.remove('open');
});
});
// ── Copy to clipboard ──
document.getElementById('install-cmd').addEventListener('click', () => {
navigator.clipboard.writeText('pip install tracecraft-ai').then(() => {
const toast = document.getElementById('copy-toast');
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), 1500);
});
});
// ── Scroll reveal (IntersectionObserver) ──
const observer = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('visible');
observer.unobserve(e.target);
}
});
}, { threshold: 0.15 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// ── Terminal typing animation ──
const terminalLines = [
{ type: 'comment', text: '# Agent 1 — Designer' },
{ type: 'cmd', text: 'tracecraft init --project my-app --agent designer' },
{ type: 'out', cls: 'out-green', text: "Initialized project 'my-app' as agent 'designer'" },
{ type: 'blank' },
{ type: 'cmd', text: 'tracecraft memory set ui.theme dark' },
{ type: 'out', cls: 'out-green', text: 'Set ui.theme = dark' },
{ type: 'blank' },
{ type: 'cmd', text: 'tracecraft send developer "Mockup ready, check artifacts"' },
{ type: 'out', cls: 'out-green', text: 'Sent to developer' },
{ type: 'blank' },
{ type: 'comment', text: '# Agent 2 — Developer' },
{ type: 'cmd', text: 'tracecraft inbox' },
{ type: 'out', cls: 'out-yellow', text: '[14:32] designer:', after: ' Mockup ready, check artifacts' },
{ type: 'blank' },
{ type: 'cmd', text: 'tracecraft memory get ui.theme' },
{ type: 'out', cls: 'out-purple', text: 'dark' },
{ type: 'blank' },
{ type: 'cmd', text: 'tracecraft claim implement' },
{ type: 'out', cls: 'out-green', text: 'Claimed step implement as developer' },
];
const termBody = document.getElementById('terminal-body');
let started = false;
function typeText(el, text, speed, cb) {
let i = 0;
const cursor = document.createElement('span');
cursor.className = 'terminal-cursor';
el.appendChild(cursor);
function tick() {
if (i < text.length) {
el.insertBefore(document.createTextNode(text[i]), cursor);
i++;
setTimeout(tick, speed);
} else {
el.removeChild(cursor);
if (cb) cb();
}
}
tick();
}
function renderTerminal() {
if (started) return;
started = true;
termBody.innerHTML = '';
let idx = 0;
function nextLine() {
if (idx >= terminalLines.length) return;
const line = terminalLines[idx++];
if (line.type === 'blank') {
termBody.appendChild(document.createElement('br'));
setTimeout(nextLine, 100);
return;
}
const div = document.createElement('div');
termBody.appendChild(div);
termBody.scrollTop = termBody.scrollHeight;
if (line.type === 'comment') {
div.innerHTML = '<span class="comment">' + line.text + '</span>';
setTimeout(nextLine, 500);
} else if (line.type === 'cmd') {
const prompt = document.createElement('span');
prompt.className = 'prompt';
prompt.textContent = '$ ';
div.appendChild(prompt);
const cmdSpan = document.createElement('span');
cmdSpan.className = 'cmd';
div.appendChild(cmdSpan);
typeText(cmdSpan, line.text, 25, () => {
setTimeout(nextLine, 400);
});
} else if (line.type === 'out') {
const span = document.createElement('span');
span.className = line.cls || '';
span.textContent = line.text;
div.appendChild(span);
if (line.after) {
div.appendChild(document.createTextNode(line.after));
}
setTimeout(nextLine, 150);
}
}
nextLine();
}
// Start typing when terminal scrolls into view
const termEl = document.querySelector('.terminal');
const termObs = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
renderTerminal();
termObs.unobserve(termEl);
}
}, { threshold: 0.3 });
termObs.observe(termEl);
// ── Active nav link highlight on scroll ──
const sections = document.querySelectorAll('section[id]');
window.addEventListener('scroll', () => {
const y = window.scrollY + 100;
sections.forEach(s => {
const link = document.querySelector('nav a[href="#' + s.id + '"]');
if (!link) return;
if (y >= s.offsetTop && y < s.offsetTop + s.offsetHeight) {
link.style.color = 'var(--text)';
} else {
link.style.color = '';
}
});
}, { passive: true });
// ── Live Feed ──
const feedEl = document.getElementById('feed-messages');
const feedStatus = document.getElementById('feed-status');
let lastFeedCount = 0;
function escFeed(s) {
const d = document.createElement('div'); d.textContent = s || ''; return d.innerHTML;
}
function feedTime(ts) {
if (!ts) return '';
const d = new Date(ts);
if (isNaN(d)) return ts.slice(11, 16) || ts;
return d.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' });
}
function renderFeed(messages) {
if (!messages.length) {
feedEl.innerHTML = '<div class="feed-empty">No messages yet — agents are warming up...</div>';
feedStatus.textContent = 'waiting';
return;
}
if (messages.length === lastFeedCount) return;
lastFeedCount = messages.length;
feedEl.innerHTML = messages.map(m => {
const from = m.from || m.sender || 'unknown';
const isDesigner = from === 'designer';
const avCls = isDesigner ? 'av-designer' : 'av-developer';
const snCls = isDesigner ? 'sn-designer' : 'sn-developer';
const initials = isDesigner ? 'D' : 'DV';
const body = escFeed(m.body || m.message || m.text || '');
// Truncate long messages for the feed
const short = body.length > 200 ? body.slice(0, 200) + '...' : body;
const ts = feedTime(m.timestamp || m.time || '');
return '<div class="feed-msg">' +
'<div class="feed-avatar ' + avCls + '">' + initials + '</div>' +
'<div class="feed-content">' +
'<div class="feed-sender ' + snCls + '">' + escFeed(from) + '</div>' +
'<div class="feed-text">' + short + '</div>' +
(ts ? '<div class="feed-time">' + ts + '</div>' : '') +
'</div>' +
'</div>';
}).join('');
feedEl.scrollTop = feedEl.scrollHeight;
feedStatus.textContent = messages.length + ' messages • live';
}
async function pollFeed() {
try {
// Try API first (FastAPI backend)
let r = await fetch('/api/messages');
if (r.ok) {
const data = await r.json();
renderFeed(data.messages || []);
return;
}
} catch {}
try {
// Fallback: static messages.json
let r = await fetch('/messages.json');
if (r.ok) {
const data = await r.json();
renderFeed(data.messages || data || []);
return;
}
} catch {}
feedStatus.textContent = 'offline — using cached';
}
// Poll every 5 seconds
pollFeed();
setInterval(pollFeed, 5000);
</script>
</body>
</html>

Xet Storage Details

Size:
33.2 kB
·
Xet hash:
6649b36eb062e4be39b9caf83f3d7884c4347d3bbb5c6c94dfcb642c0250ec36

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.