Replaces public split-brain wording with Layered Memory Fabric, documents the skills/brain/ops planes, and sketches the shared FreeBSD/Linux install contract around PostgreSQL, ZFS/OpenZFS, and platform isolation adapters.\n\nChecks: npx --yes prettier@3 --check touched docs/html; git diff --check --- Build: pass | Tests: FAIL — 1 failed
579 lines
20 KiB
HTML
579 lines
20 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>NanoClaw Upstream — Clawdie Docs</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,300;1,400&family=DM+Mono:wght@300;400&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<link rel="stylesheet" href="/css/shared.css" />
|
|
</head>
|
|
<body>
|
|
<div class="hex-bg"></div>
|
|
<div class="sidebar-overlay" id="overlay"></div>
|
|
|
|
<header class="top-bar">
|
|
<button class="mobile-menu-btn" id="menuBtn" aria-label="Toggle menu">
|
|
☰
|
|
</button>
|
|
<a href="/" class="brand"><span>△</span> Clawdie Docs</a>
|
|
<div class="nav-links">
|
|
<a href="https://clawdie.si">Home</a>
|
|
<a href="https://codeberg.org/Clawdie" target="_blank" rel="noopener"
|
|
>Source</a
|
|
>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="docs-layout">
|
|
<nav class="sidebar" id="sidebar">
|
|
<div class="sidebar-section">
|
|
<span class="section-label">Getting Started</span>
|
|
<ul>
|
|
<li><a href="/">Introduction</a></li>
|
|
<li><a href="/docs/install.html">Installation</a></li>
|
|
<li><a href="/docs/iso.html">ISO Install</a></li>
|
|
<li><a href="/docs/split-brain.html">Layered Memory</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<span class="section-label">Architecture</span>
|
|
<ul>
|
|
<li><a href="/docs/">How It Works</a></li>
|
|
<li><a href="/docs/#jails-not-docker">Jails, Not Docker</a></li>
|
|
<li><a href="/docs/#wayland-first-display">Wayland Display</a></li>
|
|
<li>
|
|
<a href="/docs/#prompt-injection-and-web-browsing"
|
|
>Prompt Injection</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/guides/nanoclaw-upstream.html" class="active"
|
|
>NanoClaw Upstream</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a
|
|
href="https://codeberg.org/Clawdie/Clawdie-AI/src/branch/main/docs/public/operate/monitoring.md"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>Monitoring</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a
|
|
href="https://codeberg.org/Clawdie/Clawdie-AI/src/branch/main/docs/public/operate/security.md"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>Security</a
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<span class="section-label">Setup Guides</span>
|
|
<ul>
|
|
<li><a href="/guides/nginx-ssl.html">Nginx + SSL</a></li>
|
|
<li><a href="/guides/tailscale-vpn.html">Tailscale VPN</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<span class="section-label">Integrations</span>
|
|
<ul>
|
|
<li><a href="/guides/stripe-agents.html">Stripe Agents</a></li>
|
|
<li><a href="/guides/protonmail.html">ProtonMail</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<span class="section-label">Project</span>
|
|
<ul>
|
|
<li><a href="/changelog.html">Changelog</a></li>
|
|
<li><a href="/license.html">License</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="content">
|
|
<div class="breadcrumb">
|
|
<a href="/">Home</a><span class="sep">/</span>
|
|
<a href="/docs/">Docs</a><span class="sep">/</span>
|
|
NanoClaw Upstream
|
|
</div>
|
|
|
|
<div class="page-header">
|
|
<h1>NanoClaw <span>Upstream</span></h1>
|
|
<p class="subtitle">
|
|
Fetch-only tracking — operator decides what to apply, nothing
|
|
auto-merges
|
|
</p>
|
|
</div>
|
|
|
|
<p>
|
|
<a
|
|
href="https://github.com/qwibitai/nanoclaw"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>NanoClaw</a
|
|
>
|
|
is an upstream project by Gavriel in the broader OpenClaw line
|
|
inspired by
|
|
<a href="https://github.com/steipete" target="_blank" rel="noopener"
|
|
>Peter Steinberger's</a
|
|
>
|
|
<a
|
|
href="https://github.com/openclaw/openclaw"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>OpenClaw</a
|
|
>. Clawdie is the FreeBSD-first fork in that lineage. The upstream
|
|
toggle lets you see what new commits are available in NanoClaw and
|
|
decide what to apply to your installation.
|
|
</p>
|
|
|
|
<div class="info-box">
|
|
<span class="info-label">Read-only by design</span>
|
|
<p>
|
|
This feature only fetches. It never merges, rebases, or modifies
|
|
your working tree. You are always in control. The agent can report
|
|
what's available; a human applies the changes.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="info-box">
|
|
<span class="info-label">Why this matters in Clawdie</span>
|
|
<p>
|
|
NanoClaw gives us the Linux-origin upstream line. Clawdie gives
|
|
operators a FreeBSD-native deployment path with jails, PF, ZFS, and
|
|
lower-friction onboarding through preloaded skills memory. Upstream
|
|
tracking is the maintainer side of that story; polished FreeBSD
|
|
bootstrap is the operator side.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="info-box">
|
|
<span class="info-label">Built on giants' shoulders</span>
|
|
<p>
|
|
OpenClaw set the broader direction. NanoClaw carried that line into
|
|
a lean upstream personal assistant. Clawdie takes the same line into
|
|
FreeBSD and the wider
|
|
<a
|
|
href="https://osa.smilepowered.org"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>OSA</a
|
|
>
|
|
stack.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>Setup</h2>
|
|
|
|
<h3>Enable upstream tracking</h3>
|
|
<p>Run once during or after initial setup:</p>
|
|
|
|
<pre><code>npx tsx setup/index.ts --step upstream --enable</code></pre>
|
|
|
|
<p>This does three things atomically:</p>
|
|
<ol>
|
|
<li>
|
|
Adds a <code>nanoclaw</code> git remote pointing to
|
|
<code>github.com/qwibitai/nanoclaw.git</code>
|
|
</li>
|
|
<li>
|
|
Runs <code>git fetch nanoclaw --no-tags</code> (read-only, no tag
|
|
pollution)
|
|
</li>
|
|
<li>
|
|
Writes <code>NANOCLAW_UPSTREAM_ENABLED=true</code> to your
|
|
<code>.env</code>
|
|
</li>
|
|
</ol>
|
|
|
|
<h3>Check status</h3>
|
|
<pre><code>npx tsx setup/index.ts --step upstream --status</code></pre>
|
|
|
|
<h3>Disable</h3>
|
|
<pre><code>npx tsx setup/index.ts --step upstream --disable</code></pre>
|
|
<p>
|
|
Sets <code>NANOCLAW_UPSTREAM_ENABLED=false</code> in
|
|
<code>.env</code>. The remote stays configured — re-enable any
|
|
time without re-fetching history.
|
|
</p>
|
|
|
|
<div class="info-box warning">
|
|
<span class="info-label">Prerequisites</span>
|
|
<p>
|
|
Clawdie must be initialised as a git repository (happens during
|
|
install). Internet access required for the initial fetch.
|
|
Subsequent fetches are incremental — only new commits are
|
|
transferred.
|
|
</p>
|
|
</div>
|
|
|
|
<h3>Not the same as skills-memory bootstrap</h3>
|
|
<p>
|
|
Upstream tracking and preloaded skills memory solve different
|
|
problems. The upstream toggle helps maintainers follow NanoClaw
|
|
evolution. The skills-memory bootstrap helps operators get through
|
|
install with fewer setup-time LLM calls by importing precomputed
|
|
vectors into a separate skills database.
|
|
</p>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>Agent tool: check_upstream_updates</h2>
|
|
|
|
<p>
|
|
Once upstream is enabled, the agent has a
|
|
<code>check_upstream_updates</code>
|
|
MCP tool available in every session. Ask from chat:
|
|
</p>
|
|
|
|
<div class="info-box">
|
|
<span class="info-label">Example conversation</span>
|
|
<p><em>"What's new in NanoClaw upstream?"</em></p>
|
|
<p>
|
|
→ Agent calls <code>check_upstream_updates</code>, reads
|
|
commits in <code>nanoclaw/main</code> not yet in
|
|
<code>HEAD</code>, and returns a readable list with a cherry-pick
|
|
hint.
|
|
</p>
|
|
</div>
|
|
|
|
<p>The tool returns one of three results:</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Situation</th>
|
|
<th>Response</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Remote not configured</td>
|
|
<td>
|
|
Instruction to run <code>--step upstream --enable</code>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Up to date</td>
|
|
<td>
|
|
"Up to date with NanoClaw upstream" (+ local-ahead count if
|
|
any)
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Commits available</td>
|
|
<td>Commit list with hashes, messages, cherry-pick hint</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>
|
|
The tool runs against the host project directory
|
|
(<code>/workspace/project</code>) from inside the agent jail —
|
|
it does not need network access and never modifies any files.
|
|
</p>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>Automatic fetch (optional cron)</h2>
|
|
|
|
<p>
|
|
The <code>scripts/fetch-upstream.ts</code> script is designed for
|
|
cron. It fetches the remote, prints a divergence summary, and exits.
|
|
Nothing is modified on the working tree.
|
|
</p>
|
|
|
|
<p>Typical weekly cron (run as the agent user):</p>
|
|
|
|
<pre><code># crontab -e (as clawdie user)
|
|
0 3 * * 1 cd /home/clawdie/clawdie-ai && npx tsx scripts/fetch-upstream.ts >> logs/upstream.log 2>&1</code></pre>
|
|
|
|
<p>Sample output:</p>
|
|
|
|
<pre><code>[13.mar.2026, 03:00:01] Fetching nanoclaw/main...
|
|
! 3 upstream commit(s) available:
|
|
a4f2c11 feat: add add-image-vision skill
|
|
9e3b881 fix: channel registry disconnect edge case
|
|
1d0a9c4 chore: bump @modelcontextprotocol/sdk to 1.9.0
|
|
(7 local commit(s) ahead of upstream)</code></pre>
|
|
|
|
<p>
|
|
Set <code>NANOCLAW_UPSTREAM_ENABLED=false</code> in
|
|
<code>.env</code>
|
|
to skip the fetch silently — useful if you need to temporarily
|
|
disable without removing the cron entry.
|
|
</p>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>Applying upstream changes</h2>
|
|
|
|
<p>
|
|
Upstream commits are never applied automatically. The standard
|
|
workflow after reviewing what's available:
|
|
</p>
|
|
|
|
<pre><code># Inspect a commit before touching your tree
|
|
git show a4f2c11
|
|
|
|
# Apply one commit
|
|
git cherry-pick a4f2c11
|
|
|
|
# Apply a range of commits
|
|
git cherry-pick 9e3b881^..a4f2c11
|
|
|
|
# Just read for ideas — the FreeBSD port often diverges intentionally
|
|
git diff HEAD...nanoclaw/main -- src/channels/registry.ts</code></pre>
|
|
|
|
<div class="info-box warning">
|
|
<span class="info-label">FreeBSD divergence is intentional</span>
|
|
<p>
|
|
NanoClaw targets Linux/Docker. Clawdie targets FreeBSD/Bastille
|
|
jails. Not every upstream commit applies cleanly — and some
|
|
shouldn't. Read before you cherry-pick. The agent can explain what
|
|
a commit does.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>Option A vs Option B</h2>
|
|
|
|
<p>
|
|
Two architectures for upstream tracking. Option A is implemented and
|
|
running. Option B is documented in Phase 7 of the refactor plan
|
|
— deferred until Option A proves insufficient.
|
|
</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Feature</th>
|
|
<th>
|
|
Option A — current <span class="tag live">live</span>
|
|
</th>
|
|
<th>
|
|
Option B — Gitea jail
|
|
<span class="tag defer">phase 7</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Upstream remote</td>
|
|
<td><code>codeberg.org</code> (public)</td>
|
|
<td>Self-hosted Gitea jail</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Infrastructure</td>
|
|
<td>None — just a git remote</td>
|
|
<td>
|
|
Gitea jail + <code>zroot/git/nanoclaw</code> ZFS dataset
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Auto-fetch</td>
|
|
<td>Optional cron script</td>
|
|
<td>Gitea mirror (hourly, webhook-triggered)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Agent visibility</td>
|
|
<td><code>check_upstream_updates</code> tool</td>
|
|
<td>
|
|
Same + <code>gitea_list_repos</code>,
|
|
<code>gitea_create_branch</code>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Applying changes</td>
|
|
<td>Manual <code>git cherry-pick</code></td>
|
|
<td>
|
|
Agent proposes branch → operator reviews PR in Gitea UI
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Private fork support</td>
|
|
<td>Not applicable</td>
|
|
<td>Full: private repos, per-agent datasets</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Internet required</td>
|
|
<td>Yes (fetch)</td>
|
|
<td>Only for initial mirror; air-gapped after</td>
|
|
</tr>
|
|
<tr>
|
|
<td>When to upgrade</td>
|
|
<td colspan="2">
|
|
When you need GitOps, private forks, or air-gapped deployment
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>
|
|
Switching from Option A to Option B: update
|
|
<code>NANOCLAW_REMOTE_URL</code> in
|
|
<code>setup/upstream.ts</code> to point to your Gitea instance,
|
|
re-run <code>--step upstream --enable</code>. The
|
|
<code>NANOCLAW_UPSTREAM_ENABLED</code>
|
|
flag and all agent tools remain the same.
|
|
</p>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section>
|
|
<h2>How it works</h2>
|
|
|
|
<p>
|
|
The <code>upstream</code> setup step lives in
|
|
<code>setup/upstream.ts</code> and registers in the standard setup
|
|
step registry in <code>setup/index.ts</code>. It uses the same
|
|
<code>emitStatus</code> / <code>logger</code> pattern as every other
|
|
setup step.
|
|
</p>
|
|
|
|
<p>
|
|
The <code>check_upstream_updates</code> MCP tool is registered
|
|
directly in
|
|
<code>jail/agent-runner/src/ipc-mcp-stdio.ts</code> — the same
|
|
server used for task scheduling and messaging. It calls
|
|
<code>git log HEAD..nanoclaw/main --oneline --no-merges</code>
|
|
against <code>/workspace/project</code> (the host repo mounted
|
|
read-only into the jail) and returns the result as text.
|
|
</p>
|
|
|
|
<p>
|
|
The cron script at <code>scripts/fetch-upstream.ts</code> runs on
|
|
the host (not inside a jail) and is intentionally minimal — it
|
|
has no dependencies beyond Node.js and git.
|
|
</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>File</th>
|
|
<th>Purpose</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>setup/upstream.ts</code></td>
|
|
<td>Setup step: enable/disable/fetch/status</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>setup/index.ts</code></td>
|
|
<td>Registers <code>upstream</code> in STEPS registry</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>scripts/fetch-upstream.ts</code></td>
|
|
<td>Cron-safe host-side fetch script</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>jail/agent-runner/src/ipc-mcp-stdio.ts</code></td>
|
|
<td>Registers <code>check_upstream_updates</code> MCP tool</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>.env</code></td>
|
|
<td><code>NANOCLAW_UPSTREAM_ENABLED</code> toggle flag</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
|
|
<footer>
|
|
<div class="footer-left">
|
|
<a href="https://clawdie.si">Clawdie AI</a> ·
|
|
<a
|
|
href="https://osa.smilepowered.org"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>OSA — Mission Statement</a
|
|
>
|
|
· NanoClaw Upstream<br />
|
|
<a
|
|
href="https://codeberg.org/Clawdie/Clawdie-AI/src/branch/main/html/docs-clawdie-si/guides/nanoclaw-upstream.html"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>Page source</a
|
|
>
|
|
·
|
|
<a
|
|
href="https://codeberg.org/Clawdie/Clawdie-AI/src/branch/main/docs/internal/nanoclaw-architecture-final.md"
|
|
target="_blank"
|
|
rel="noopener"
|
|
>Architecture</a
|
|
><br />
|
|
Last updated: 13.mar.2026
|
|
</div>
|
|
<div class="footer-hex">△</div>
|
|
</footer>
|
|
</main>
|
|
|
|
<aside class="toc">
|
|
<p class="toc-title">On this page</p>
|
|
<nav id="toc-list"></nav>
|
|
</aside>
|
|
</div>
|
|
|
|
<script>
|
|
const toc = document.getElementById('toc-list');
|
|
if (toc) {
|
|
document.querySelectorAll('.content h2, .content h3').forEach((h) => {
|
|
if (!h.id)
|
|
h.id = h.textContent
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-');
|
|
const a = document.createElement('a');
|
|
a.href = '#' + h.id;
|
|
a.className = 'toc-link' + (h.tagName === 'H3' ? ' toc-sub' : '');
|
|
a.textContent = h.textContent;
|
|
toc.appendChild(a);
|
|
});
|
|
}
|
|
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((e, i) => {
|
|
if (e.isIntersecting)
|
|
setTimeout(() => e.target.classList.add('visible'), i * 80);
|
|
});
|
|
},
|
|
{ threshold: 0.08 },
|
|
);
|
|
document.querySelectorAll('section').forEach((s) => observer.observe(s));
|
|
|
|
const menuBtn = document.getElementById('menuBtn');
|
|
const sidebar = document.getElementById('sidebar');
|
|
const overlay = document.getElementById('overlay');
|
|
if (menuBtn && sidebar) {
|
|
menuBtn.addEventListener('click', () => {
|
|
sidebar.classList.toggle('open');
|
|
overlay?.classList.toggle('open');
|
|
});
|
|
overlay?.addEventListener('click', () => {
|
|
sidebar.classList.remove('open');
|
|
overlay.classList.remove('open');
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|