FallSeed · HR Firm
Progressive Web App · single HTML · prime 1049 · ◊·κ=1
.
'; let baseUserMsg = `Generate a complete sovereign HTML tool for this need: "${prompt}" CONTEXT — the user's existing HR T0 rules (reference what's relevant in your tool's Q&A panel): ${SEED.t0Rules.map(r => `- ${r.pattern} → ${r.answer}`).join('\n')} EXISTING WEDGE BASE TOOLS (your new tool meshes with these via fall-hr BroadcastChannel): ${SEED.baseTools.map(t => `- ${t.name} (${t.role}, prime ${t.prime}): ${t.purpose}`).join('\n')} OUTPUT: complete single HTML file. Start with . End with . No preamble. No code fences.`; // V2 · if refining, prepend existing HTML let refineSource = null; if (refineSourceId) { refineSource = state.generated.find(g => g.id === refineSourceId); if (refineSource) { baseUserMsg = `Here is an existing tool you previously generated: <<>> ${refineSource.html} <<>> The user wants to refine it. Their modification request: "${prompt}" OUTPUT the complete updated HTML file with the modification applied. Preserve everything that works. Start with . End with . No preamble. No code fences.`; } } try { const result = await runCascadeStream(SEED.buildPromptSystem, baseUserMsg, 16000, (currentText) => { // Render incremental text in code panel + try to render in iframe out.textContent = currentText.length > 12000 ? currentText.slice(-12000) : currentText; out.scrollTop = out.scrollHeight; // Try to render iframe if we have enough HTML start if (currentText.includes(' 500) { try { iframe.srcdoc = currentText + (currentText.includes('') ? '' : '\n'); } catch(e){} } }, renderCascadeTrace ); let html = result.text.replace(/^```html\n?/, '').replace(/\n?```\s*$/, '').trim(); if (!html.startsWith('([^<]+)<\/title>/i); const primeMatch = html.match(/ 8000 ? '\n\n... (' + (html.length - 8000) + ' more bytes — full file in download)' : ''); $('#downloadBtn').disabled = false; $('#openBtn').disabled = false; const blob = new Blob([html], { type: 'text/html' }); const url = URL.createObjectURL(blob); iframe.src = url; placeholder.style.display = 'none'; $('#buildStatus').innerHTML = `✓ ${nameGuess} via ${result.provider.name} · ${html.length.toLocaleString()} chars · ${result.tokensIn}→${result.tokensOut} tokens${result.provider.paid?' · ~£'+((result.tokensIn*result.provider.pricePer1MIn+result.tokensOut*result.provider.pricePer1MOut)/1000000).toFixed(4):''}`; toast('Generated via ' + result.provider.name); render(); // refresh generated-tools list } catch (e) { out.classList.remove('streaming'); out.textContent = '❌ ' + e.message; $('#buildStatus').innerHTML = `cascade failed`; toast('Build failed'); } finally { btn.disabled = false; btn.textContent = 'Generate tool (streaming)'; } } function refineGenerated(id) { const g = state.generated.find(x => x.id === id); if (!g) return; refineSourceId = id; switchTab('build'); setTimeout(() => { $('#buildPrompt').value = ''; $('#buildPrompt').placeholder = `Refining ${g.toolName} (v${g.version||1}). Describe what to change. e.g. "Add a CSV export button", "Add a department filter", "Fix the date format to UK"`; $('#buildPrompt').focus(); $('#buildStatus').innerHTML = `↻ refining ${g.toolName} v${g.version||1} → v${(g.version||1)+1}`; }, 100); } function downloadGenerated() { if (!lastGenerated) return; const blob = new Blob([lastGenerated.html], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = lastGenerated.toolName + '.html'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); toast('Downloaded ' + lastGenerated.toolName + '.html'); } function openGenerated() { if (!lastGenerated) return; const blob = new Blob([lastGenerated.html], { type: 'text/html' }); window.open(URL.createObjectURL(blob), '_blank'); } function reopenGenerated(id) { const g = state.generated.find(x => x.id === id); if (!g) return; const blob = new Blob([g.html], { type: 'text/html' }); window.open(URL.createObjectURL(blob), '_blank'); } function redownloadGenerated(id) { const g = state.generated.find(x => x.id === id); if (!g) return; const blob = new Blob([g.html], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = g.toolName + '.html'; document.body.appendChild(a); a.click(); a.remove(); } // ═══════════════════════════════════════════════════════════════ // V2 · PROVIDERS WITH QUOTA + AUTO-DETECT FLAGS // ═══════════════════════════════════════════════════════════════ function renderProviders(v) { v.innerHTML = `

LLM Providers

cascade · sovereign first · paid last · ${state.autoDetected.length} auto-detected
Cascade tries providers in priority order. v2 auto-detected: ${state.autoDetected.length?state.autoDetected.map(id => PROVIDERS.find(p=>p.id===id)?.name).join(', '):'none (start ollama on :11434 or LM Studio on :1234 and reload)'}
${PROVIDERS.map(p => { const cfg = state.providerConfig[p.id] || {}; const rl = state.rateLimits[p.id]; const isRL = rl && rl.until > now(); const u = state.usage[p.id] || { totalIn:0, totalOut:0, calls:0 }; const cost = p.paid ? (u.totalIn*p.pricePer1MIn + u.totalOut*p.pricePer1MOut)/1000000 : 0; const autoDetected = state.autoDetected.includes(p.id); return `
${p.tier}
${esc(p.name)} ${autoDetected?'● AUTO':''}
${esc(p.note)}
${isRL?'rate-limited':p.tierLabel}
${p.signupUrl?`↗ key`:'
'}
${p.requiresKey?`
`:''} ${p.id==='webllm'?`
Status: ${state.webllmStatus} ${navigator.gpu?'· WebGPU ✓':'· WebGPU NOT available — needs Chrome 113+'}
`:''} ${p.tier==='T2'?`
Endpoint: ${esc(p.endpoint)} ·
`:''} ${p.requiresKey?`
`:''}
${u.calls} calls
in ${u.totalIn.toLocaleString()} · out ${u.totalOut.toLocaleString()} · total ${(u.totalIn+u.totalOut).toLocaleString()} tokens
${p.paid?('£'+cost.toFixed(4)):'free'}
`; }).join('')}

Cascade test

`; } async function toggleProvider(id) { state.providerConfig[id].enabled = !state.providerConfig[id].enabled; state.providerConfig[id].userToggled = true; await persistProviderConfig(); render(); } async function updateProviderKey(id, key) { state.providerConfig[id].key = key.trim(); await persistProviderConfig(); updateTierBadge(); toast('Key saved'); } async function updateProviderModel(id, model) { state.providerConfig[id].customModel = model.trim(); await persistProviderConfig(); toast('Model override saved'); } async function testProvider(id) { const p = PROVIDERS.find(x => x.id === id); const el = $('#ptest_' + id); if (!p) return; el.innerHTML = ' testing...'; const avail = await providerAvailable(p); if (!avail.ok) { el.innerHTML = ` ✗ ${esc(avail.reason)}`; return; } el.innerHTML = ' ✓ reachable'; } async function testCascade() { const el = $('#cascadeTestResult'); el.innerHTML = '
running cascade...
'; let streamText = ''; try { const result = await runCascadeStream( 'You are a test. Reply with exactly one word.', 'Say hi.', 30, (t) => { streamText = t; el.querySelector('.cascade-trace').innerHTML += ''; }, // updates per token but we just need final (trace) => el.innerHTML = '
' + trace.map(t => `
${t.status.toUpperCase().padEnd(4)}${esc(t.provider)} · ${esc(t.reason)}${t.ms?' · '+t.ms+'ms':''}
`).join('') + '
' ); el.innerHTML += `
✓ "${esc(result.text.trim().slice(0,80))}" from ${esc(result.provider.name)} (${result.model})
`; } catch (e) { el.innerHTML += `
✗ ${esc(e.message)}
`; } } // ═══════════════════════════════════════════════════════════════ // V2 · PACKAGER · fork this seed into a new vertical // ═══════════════════════════════════════════════════════════════ function ensureDraft() { if (!state.pkgDraft) state.pkgDraft = JSON.parse(JSON.stringify(SEED)); return state.pkgDraft; } function renderPackager(v) { const d = ensureDraft(); v.innerHTML = `

Fork Seed

turn this HR seed into a seed for any other vertical
The strategic mechanic. Edit the seed fields below — rename vertical, swap T0 rules, swap base-tool URLs, swap document clauses, rewrite the build prompt — then click Download fallseed-{vertical}-v1.html. You get a complete new installer.html for any vertical (clinic, vet, recruit, construction, marketing, pharmacy, dentist, education, hospitality, transport, anything). Same shape, different substrate. 5 minutes to spin up a sellable seed for a new industry.

Manifest

Base tools (${d.baseTools.length})

URLs of the 4 live wedge tools for this vertical. Edit or replace with your new vertical's URLs.

${d.baseTools.map((t,i) => `
`).join('')}

T0 rules (${d.t0Rules.length})

Hard-coded regulatory Q&A pairs. Pattern is a regex; answer is plain text. Replace the HR rules with rules for your new vertical (e.g. CQC for clinic, RCVS for vet, MCOB for mortgage).

${d.t0Rules.map((r,i) => `
`).join('')}

Compliance checklist (${d.complianceItems.length})

${d.complianceItems.map((c,i) => `
`).join('')}

Locked clauses (${d.documentClauses.length})

${d.documentClauses.map((c,i) => `
`).join('')}

Build-prompt (the LLM's instructions for generating new tools in this vertical)

Export the forked seed

Download a complete installer-{vertical}-v1.html that ships with all your edits. It's a working FallSeed for your new vertical, ready to use or sell.

`; } function updateDraftField(path, value) { const d = ensureDraft(); const parts = path.split('.'); let cur = d; for (let i=0; i r.text()).then(currentHtml => { // Find the SEED_DEFAULT object literal and replace it const seedStart = currentHtml.indexOf('const SEED_DEFAULT = {'); if (seedStart < 0) { toast('Cannot find SEED_DEFAULT in source'); return; } // Find matching close brace + semicolon — walk braces let depth = 0, end = -1; for (let i = seedStart + 'const SEED_DEFAULT = '.length; i < currentHtml.length; i++) { const c = currentHtml[i]; if (c === '{') depth++; else if (c === '}') { depth--; if (depth === 0) { end = i + 1; break; } } } if (end < 0) { toast('Cannot parse SEED_DEFAULT'); return; } const newSeedLiteral = 'const SEED_DEFAULT = ' + jsLiteral(d); const newHtml = currentHtml.slice(0, seedStart) + newSeedLiteral + currentHtml.slice(end); const blob = new Blob([newHtml], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'fallseed-' + (d.manifest.name||'forked') + '-v1.html'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); toast('Downloaded fallseed-' + d.manifest.name + '-v1.html (' + Math.round(newHtml.length/1024) + ' KB)'); }).catch(e => toast('Fetch failed: ' + e.message)); } // Render a JS object as a JS literal (not JSON) so it parses with template literals etc. function jsLiteral(obj, indent = 0) { const pad = ' '.repeat(indent); const padNext = ' '.repeat(indent+1); if (obj === null) return 'null'; if (typeof obj === 'string') return '`' + obj.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${') + '`'; if (typeof obj === 'number' || typeof obj === 'boolean') return String(obj); if (Array.isArray(obj)) { if (!obj.length) return '[]'; return '[\n' + obj.map(v => padNext + jsLiteral(v, indent+1)).join(',\n') + '\n' + pad + ']'; } if (typeof obj === 'object') { const keys = Object.keys(obj); if (!keys.length) return '{}'; return '{\n' + keys.map(k => padNext + (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k)?k:JSON.stringify(k)) + ': ' + jsLiteral(obj[k], indent+1)).join(',\n') + '\n' + pad + '}'; } return JSON.stringify(obj); } // ═══════════════════════════════════════════════════════════════ // INSPECT + SETTINGS // ═══════════════════════════════════════════════════════════════ function renderInspect(v) { v.innerHTML = `

Inspect Seed

currently loaded · use Fork Seed to edit
${SEED.baseTools.length}
Base tools
${SEED.t0Rules.length}
T0 rules
${SEED.complianceItems.length}
Compliance items
${SEED.documentClauses.length}
Locked clauses
${PROVIDERS.length}
LLM providers
${SEED.manifest.prime}
Seed prime

Manifest

${esc(JSON.stringify(SEED.manifest, null, 2))}

T0 rules

${SEED.t0Rules.map(r => `
${esc(r.pattern)}
${esc(r.answer)}
`).join('')}

Build-prompt system instruction

${esc(SEED.buildPromptSystem)}
`; } function renderSettings(v) { const totalCost = PROVIDERS.filter(p => p.paid).reduce((s,p) => { const u = state.usage[p.id] || {totalIn:0,totalOut:0}; return s + (u.totalIn*p.pricePer1MIn + u.totalOut*p.pricePer1MOut)/1000000; }, 0); v.innerHTML = `

Settings

${state.generated.length}
Tools generated
${Object.values(state.usage).reduce((s,u)=>s+u.calls,0)}
Total cascade calls
£${totalCost.toFixed(4)}
Total spent (paid providers)
${state.firm?'1':'0'}
Firm provisioned

Data

Where do my keys live?

In your browser's IndexedDB only. Each LLM call goes browser → that provider's API directly. For ollama/lmstudio: OLLAMA_ORIGINS=* ollama serve

`; } function exportAll() { const data = { seed: 'fallseed-clinic-v2', exportedAt: now(), firm: state.firm, providerConfig: { ...state.providerConfig }, usage: state.usage, generatedCount: state.generated.length, forkedSeedManifest: SEED.manifest }; for (const id in data.providerConfig) data.providerConfig[id] = { ...data.providerConfig[id], key: data.providerConfig[id].key ? '[redacted]' : '' }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'fallseed-export.json'; document.body.appendChild(a); a.click(); a.remove(); toast('Exported (keys redacted)'); } async function wipeAll() { if (!confirm('Wipe all FallSeed data including keys?')) return; for (const s of ['config','generated']) { const tx = db.transaction(s,'readwrite'); tx.objectStore(s).clear(); await new Promise(r => tx.oncomplete = r); } location.reload(); } (async function boot() { try { await openDB(); await loadAll(); initMesh(); render(); // V2 · auto-detect local runners in background, re-render when done autoDetectProviders().then(() => render()); } catch (e) { console.error('boot error', e); $('#view').innerHTML = '
Boot error: ' + esc(e.message) + '
'; } })();