A reference copy of the finished file (1939 lines, `node --check` clean, smoke green) and unified diffs for every touched file sit on Celeste's box at `/workspace/flint-pastes/agent-bridge-lock-reference-v0.1/`, sha256 in `SHA256SUMS`. Applying those diffs to a clean `f86b317` tree reproduces the scratch build exactly. If Kirk hands them over, you may diff against them. The blocks below are the same code. ## Exact source excerpt, characters 23094–23272 **Step 1.** Keep line 27 exactly as it is (layer). Insert **Block A** right after line 34 (`if (!fs.existsSync(DATA_DIR)) ...`), because the trust file needs `DATA_DIR` to exist. ## Exact source excerpt, characters 23274–23421 **Step 2.** Replace the body of `handleRequest` (L111-129) with **Block B**. The old `Access-Control-Allow-Origin: *` line is superseded inside it. ## Exact source excerpt, characters 23423–23642 **Step 3.** Change the `route` signature at L131 to `function route(url, method, data, res, actingAs, meta) {`. After L133 (`var activeId = actingAs || activeId;`), insert **Block C** (pairing and trusted-minds routes). ## Exact source excerpt, characters 23644–23902 **Step 4.** In the heartbeat object, right after L140 `version: '5.8.0',`, add four lines: ```js bridgeLock: BRIDGE_LOCK_VERSION, auth: 'token-required', pairing: 'code', trustedMinds: bridgeEphemeral ? 'ephemeral' : 'persistent', ``` ## Exact source excerpt, characters 23904–24067 **Step 5.** Replace L992-1140 (from the `LATTICE CODE` banner through the end of `/code/test`) with **Block D**. Keep the `// ── 404 ──` fallthrough at L1142-1143. ## Exact source excerpt, characters 24069–24473 **Step 6.** Replace L1153-1157 (`var server = ...` through the `Listening on` log) with **Block E**. The remaining console lines (L1158-1181) stay as they are. Block E runs the command-line trust tools first; when one ran, the port never opens. The `if (BRIDGE_CLI_DONE) {} else server.listen(PORT, BRIDGE_HOST, ...)` shape keeps the plain `server.listen(PORT, BRIDGE_HOST` text that the smoke looks for. ## Exact source excerpt, characters 24475–24547 ### Block A: helpers, trusted minds, command line (insert after line 34) ## Exact source excerpt, characters 24549–26163 ```js // ═══════════════════════════════════════════════════ // LAYER bridge-lock-v0 · v0.1 (2026-09-28): the door lock. Marker: v-agent-bridge-lock-v0 // Celeste's brief, built by Flint. Nothing above is removed. // Strangers stay out. Trusted minds keep their full local reach // (docs/library/AUTONOMY.md, Principle 1: local autonomy is absolute). // 1. Listen on 127.0.0.1 only (no env override, never 0.0.0.0). // 2. Named Origin allowlist, never bare *: FreeLattice, the Lattice Tree, // local dev, the Tauri shell, plus exact origins Kirk adds by command line. // 3. Host header must be 127.0.0.1 or localhost (DNS-rebinding guard). // 4. Trusted minds: one token per device, given once through a short pairing // code, kept only as a SHA-256 hash in ~/.freelattice/agent-bridge-trusted.json // (0600) until Kirk revokes it. No expiry by default. // FL_BRIDGE_EPHEMERAL=1 brings back the old forget-on-restart behavior. // 5. Local tools on this computer are trusted by default. They read their // token from ~/.freelattice/agent-bridge-token (0600) and never pair. // 6. git / grep / node run through execFileSync / spawnSync argument arrays. // No shell. Paths are realpath-checked inside a trusted project folder. // 7. Body size cap. Malformed JSON is refused. // 8. Every commit request and every trust change goes into a hash-chained, // content-free ledger: ~/.freelattice/bridge-ledger.jsonl // This bridge (3141) is NOT the Ollama Bridge (bridge/, port 11435). // ═══════════════════════════════════════════════════ const { execFileSync, spawnSync } = require('child_process'); ## Exact source excerpt, characters 26165–26452 const BRIDGE_LOCK_VERSION = 'v0.1'; const BRIDGE_HOST = '127.0.0.1'; const MAX_BODY_BYTES = 8 * 1024 * 1024; // docs/app.html is ~2.9 MB; JSON escaping adds some const MAX_COMMIT_MESSAGE = 4000; const MAX_COMMIT_FILES = 200; var bridgeEphemeral = process.env.FL_BRIDGE_EPHEMERAL === '1'; ## Exact source excerpt, characters 26454–26955 /** Built-in origins. Never bare *. Same shape as bridge/proxy-core.js. */ const ALLOWED_ORIGIN_PATTERNS = [ /^https:\/\/(www\.)?freelattice\.com$/i, /^https:\/\/(www\.)?thelatticetree\.com$/i, /^http:\/\/localhost(:\d{1,5})?$/i, // local dev of docs/ (e.g. python -m http.server) /^http:\/\/127\.0\.0\.1(:\d{1,5})?$/i, // same, by IP /^tauri:\/\/localhost$/i, // Tauri desktop shell (macOS, Linux) /^https?:\/\/tauri\.localhost$/i // Tauri desktop shell (Windows) ]; ## Exact source excerpt, characters 26957–27441 /** An exact origin Kirk may add: scheme://host[:port], nothing else. Never a wildcard. */ function exactOrigin(o) { o = String(o || '').trim().toLowerCase(); if (!o || o.length > 200 || o.indexOf('*') !== -1 || hasControlChars(o)) return null; var m = o.match(/^(https?):\/\/([a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*)(:(\d{1,5}))?$/); if (!m) return null; if (m[7] && (parseInt(m[7], 10) < 1 || parseInt(m[7], 10) > 65535)) return null; return o; } ## Exact source excerpt, characters 27443–27689 function originAllowed(origin) { if (!origin) return false; var o = String(origin); if (ALLOWED_ORIGIN_PATTERNS.some(function (re) { return re.test(o); })) return true; return trustState().trustedOrigins.indexOf(o.toLowerCase()) !== -1; } ## Exact source excerpt, characters 27691–27797 function hostAllowed(host) { return /^(127\.0\.0\.1|localhost)(:\d{1,5})?$/i.test(String(host || '')); } ## Exact source excerpt, characters 27799–27902 function sha256Hex(s) { return crypto.createHash('sha256').update(String(s), 'utf8').digest('hex'); } ## Exact source excerpt, characters 27904–27985 function hasControlChars(s) { return /[\u0000-\u001f\u007f]/.test(String(s)); } ## Exact source excerpt, characters 27987–28590 // ── Trusted minds (persistent, revocable, hashed) ── const TRUST_FILE = path.join(DATA_DIR, 'agent-bridge-trusted.json'); const TOKEN_FILE = path.join(DATA_DIR, 'agent-bridge-token'); const BRIDGE_SCOPES = ['read', 'write', 'patch', 'test', 'commit', 'wallet', 'manage', 'secrets']; // Full local power by default (AUTONOMY.md Principle 1). Only 'secrets' // (reading and writing .env files) is opt-in, one mind at a time. const DEFAULT_SCOPES = ['read', 'write', 'patch', 'test', 'commit', 'wallet', 'manage']; const MIND_KINDS = ['browser', 'tool', 'cli', 'remote']; const TOUCH_SAVE_MS = 60 * 1000; ## Exact source excerpt, characters 28592–28807 var trust = null; // { version, minds, trustedOrigins, roots, localTools, idleExpiryDays } var trustStamp = ''; // file identity at last load or save, so command-line edits apply live var lastTouchSave = 0; ## Exact source excerpt, characters 28809–31145 function fileStamp(f) { try { var s = fs.statSync(f); return s.ino + ':' + s.size + ':' + s.mtimeMs; } catch (e) { return 'none'; } } function cleanName(s) { return String(s || '').replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, 60); } function cleanScopes(list) { if (!Array.isArray(list)) return DEFAULT_SCOPES.slice(); var out = []; list.forEach(function (s) { if (BRIDGE_SCOPES.indexOf(s) !== -1 && out.indexOf(s) === -1) out.push(s); }); return out; } function emptyTrust() { return { version: 1, minds: [], trustedOrigins: [], roots: {}, localTools: true, idleExpiryDays: 0 }; } function cleanTrust(raw) { var t = emptyTrust(); if (!raw || typeof raw !== 'object') return t; if (Array.isArray(raw.minds)) { t.minds = raw.minds.filter(function (m) { return m && typeof m.id === 'string' && /^[a-f0-9]{8,32}$/.test(m.id) && typeof m.tokenSha256 === 'string' && /^[a-f0-9]{64}$/.test(m.tokenSha256); }).map(function (m) { return { id: m.id, name: cleanName(m.name) || 'A trusted mind', origin: typeof m.origin === 'string' ? m.origin.slice(0, 200) : '', kind: MIND_KINDS.indexOf(m.kind) !== -1 ? m.kind : 'browser', scopes: cleanScopes(m.scopes), tokenSha256: m.tokenSha256, createdAt: typeof m.createdAt === 'string' ? m.createdAt : '', lastUsedAt: typeof m.lastUsedAt === 'string' ? m.lastUsedAt : '', expiresAt: typeof m.expiresAt === 'string' ? m.expiresAt : null }; }); } if (Array.isArray(raw.trustedOrigins)) { raw.trustedOrigins.forEach(function (o) { var e = exactOrigin(o); if (e && t.trustedOrigins.indexOf(e) === -1) t.trustedOrigins.push(e); else if (!e) console.error(' ! Ignored trusted origin (exact scheme://host[:port] only, never *): ' + String(o).slice(0, 80)); }); } if (raw.roots && typeof raw.roots === 'object' && !Array.isArray(raw.roots)) { Object.keys(raw.roots).forEach(function (k) { if (/^[a-z0-9][a-z0-9_-]{0,31}$/i.test(k) && k !== 'project' && typeof raw.roots[k] === 'string' && path.isAbsolute(raw.roots[k])) t.roots[k] = raw.roots[k]; }); } if (raw.localTools === false) t.localTools = false; var d = parseInt(raw.idleExpiryDays, 10); if (d > 0 && d < 36500) t.idleExpiryDays = d; return t; } ## Exact source excerpt, characters 31147–31951 /** Current trust, reloaded whenever the file changes (so a command-line revoke applies at once). */ function trustState() { var stamp = fileStamp(TRUST_FILE); if (!trust || stamp !== trustStamp) { var raw = null; if (stamp !== 'none') { try { raw = JSON.parse(fs.readFileSync(TRUST_FILE, 'utf8')); } catch (e) { var aside = TRUST_FILE + '.unreadable-' + Date.now(); try { fs.renameSync(TRUST_FILE, aside); } catch (e2) {} console.error(' ! Trust file was unreadable. Kept it as ' + aside + ' and started fresh.'); stamp = 'none'; } } var fresh = cleanTrust(raw); if (bridgeEphemeral) fresh.minds = trust ? trust.minds : []; // ephemeral: minds live in memory only trust = fresh; trustStamp = stamp; } return trust; } ## Exact source excerpt, characters 31953–32647 function saveTrust() { if (bridgeEphemeral) return true; // nothing about minds touches disk in ephemeral mode var t = trustState(); var out = { version: 1, minds: t.minds, trustedOrigins: t.trustedOrigins, roots: t.roots, localTools: t.localTools, idleExpiryDays: t.idleExpiryDays }; var tmp = TRUST_FILE + '.tmp-' + process.pid; try { fs.writeFileSync(tmp, JSON.stringify(out, null, 2) + '\n', { mode: 0o600 }); try { fs.chmodSync(tmp, 0o600); } catch (e) {} fs.renameSync(tmp, TRUST_FILE); trustStamp = fileStamp(TRUST_FILE); return true; } catch (e) { console.error(' ! Could not save trusted minds: ' + e.message); return false; } } ## Exact source excerpt, characters 32649–32790 function newToken() { return crypto.randomBytes(32).toString('hex'); } function newMindId() { return crypto.randomBytes(4).toString('hex'); } ## Exact source excerpt, characters 32792–33590 /** The trusted mind a token belongs to, or null. Compares SHA-256 hashes in constant time. */ function mindForToken(t) { t = String(t || ''); if (!/^[a-f0-9]{64}$/.test(t)) return null; var h = Buffer.from(sha256Hex(t), 'hex'); var st = trustState(); var hit = null; st.minds.forEach(function (m) { var mh = Buffer.from(m.tokenSha256, 'hex'); if (mh.length === h.length && crypto.timingSafeEqual(mh, h)) hit = m; }); if (!hit) return null; if (hit.kind === 'cli' && !st.localTools) return null; var now = Date.now(); if (hit.expiresAt && Date.parse(hit.expiresAt) < now) return null; if (st.idleExpiryDays) { var seen = Date.parse(hit.lastUsedAt || hit.createdAt || '') || now; if (now - seen > st.idleExpiryDays * 86400000) return null; } return hit; } ## Exact source excerpt, characters 33592–33781 function requestMind(req) { return mindForToken(req.headers['x-fl-bridge-token']); } // Kept from v0 so older callers read the same way. function tokenOk(req) { return !!requestMind(req); } ## Exact source excerpt, characters 33783–33946 function touchMind(m) { m.lastUsedAt = new Date().toISOString(); if (Date.now() - lastTouchSave > TOUCH_SAVE_MS) { lastTouchSave = Date.now(); saveTrust(); } } ## Exact source excerpt, characters 33948–34200