feat(iso): stage colibri test agent and provider key help (Sam & Codex) #54
7 changed files with 76 additions and 73 deletions
2
BUILD.md
2
BUILD.md
|
|
@ -82,7 +82,7 @@ Colibri-backed. The image includes:
|
|||
```text
|
||||
/usr/local/bin/colibri-daemon
|
||||
/usr/local/bin/colibri
|
||||
/usr/local/bin/colibri-smoke-agent
|
||||
/usr/local/bin/colibri-test-agent
|
||||
/usr/local/bin/colibri-mcp # MCP bridge for Zed/Claude Code/Cursor
|
||||
/usr/local/bin/colibri-tui # if present in the artifact dir
|
||||
/usr/local/etc/rc.d/colibri_daemon
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ sudo mdconfig -d -u md0
|
|||
## Level 2: bhyve Verification Gate
|
||||
|
||||
Use bhyve as the standard pre-hardware gate when the ML350p lane is available.
|
||||
This is no longer just an opportunistic smoke test; it is the default
|
||||
This is no longer just an opportunistic startup check; it is the default
|
||||
middle-stage verification between static artifact checks and physical hardware.
|
||||
|
||||
Treat bhyve as authoritative for boot/runtime plumbing and still treat real
|
||||
|
|
@ -558,7 +558,7 @@ proprietary NVIDIA stack.
|
|||
Linux baseline probe:
|
||||
[linux-hardware.org/?probe=efd5b5b389](https://linux-hardware.org/?probe=efd5b5b389)
|
||||
|
||||
This is a real deploy target. First-boot smoke set for this machine
|
||||
This is a real deploy target. First-boot check set for this machine
|
||||
(or any AMD Ryzen U-series laptop) once the image lands:
|
||||
|
||||
```sh
|
||||
|
|
@ -783,7 +783,7 @@ mdo -u root fwget -n # dry run
|
|||
### What to do when the chipset is unsupported
|
||||
|
||||
The live USB image is still useful — all daemons bind to `lo0` too, so
|
||||
`sshd`, Avahi, and the local stack can be smoke-tested without network.
|
||||
`sshd`, Avahi, and the local stack can be validated without network.
|
||||
For end-to-end validation, swap to a supported dongle from the lists
|
||||
above.
|
||||
|
||||
|
|
@ -1069,7 +1069,7 @@ Mark the image good only when all of these are true:
|
|||
- [ ] `/` is read-write, `/tmp` and `/var/log` are tmpfs, and `/var/tmp` stays on disk
|
||||
- [ ] `~/.cache` points at `/tmp/clawdie/cache`
|
||||
- [ ] `/usr/local/etc/xdg/xfce4/xinitrc` and `clawdie` xinitrc fallbacks are executable
|
||||
- [ ] `xinit`/`startx`, `clawdie-startx`, `clawdie-gui`, and `xterm` are present for minimal Xorg rescue/smoke testing
|
||||
- [ ] `xinit`/`startx`, `clawdie-startx`, `clawdie-gui`, and `xterm` are present for minimal Xorg rescue/startup checking
|
||||
- [ ] `/var/lib/xkb` exists and XKB keymap compilation succeeds
|
||||
- [ ] `XDG_RUNTIME_DIR` resolves to `/var/run/user/<uid>`
|
||||
- [ ] `clawdie_live_gpu` log shows a sensible path or a clear fallback
|
||||
|
|
|
|||
5
build.sh
5
build.sh
|
|
@ -337,7 +337,7 @@ preflight_colibri_artifacts() {
|
|||
echo " Set COLIBRI_REPO=/path/to/colibri or FEATURE_COLIBRI=NO."
|
||||
exit 1
|
||||
fi
|
||||
for _colibri_bin in colibri-daemon colibri colibri-smoke-agent colibri-mcp; do
|
||||
for _colibri_bin in colibri-daemon colibri colibri-test-agent colibri-mcp; do
|
||||
if [ ! -x "${_resolved_colibri_artifact_dir}/${_colibri_bin}" ]; then
|
||||
echo "ERROR: Colibri release binary missing: ${_resolved_colibri_artifact_dir}/${_colibri_bin}"
|
||||
command -v cargo >/dev/null 2>&1 || \
|
||||
|
|
@ -818,6 +818,7 @@ install_colibri_service() {
|
|||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'colibri_daemon_socket="/var/run/colibri/colibri.sock"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'colibri_daemon_db_path="/var/db/colibri/colibri.sqlite"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'colibri_daemon_logfile="/var/log/colibri/daemon.log"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'colibri_daemon_provider_env="/usr/local/etc/colibri/provider.env"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'colibri_daemon_host="$(hostname)"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" "colibri_cost_mode=\"${COLIBRI_COST_MODE:-smart}\""
|
||||
|
||||
|
|
@ -851,7 +852,7 @@ install_colibri_service() {
|
|||
_now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
sqlite3 "${_colibri_db}" "INSERT OR IGNORE INTO skills (id, name, description, category, created_at) VALUES
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000001)', 'freebsd-live-usb', 'FreeBSD live USB operator workstation procedures', 'freebsd', '${_now}'),
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000002)', 'colibri-smoke', 'Colibri daemon smoke test and validation', 'colibri', '${_now}'),
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000002)', 'colibri-test', 'Colibri daemon startup check and validation', 'colibri', '${_now}'),
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000003)', 'iso-build', 'Clawdie ISO build and staging workflow', 'iso', '${_now}'),
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000004)', 'tailscale-join', 'Tailscale mesh join procedure for operator USB', 'networking', '${_now}'),
|
||||
('$(uuidgen || echo 00000000-0000-0000-0000-000000000005)', 'disk-deploy', 'Deploy from USB live to permanent disk install. Provisions ZFS pool, installs FreeBSD boot environment, migrates config, and prepares for the future deployed-system clawdie service.', 'clawdie', '${_now}'),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ For rebuilds, clone a fresh working checkout into a separate directory such as
|
|||
|
||||
## Required live packages
|
||||
|
||||
Future ISOs should include these packages to make this path available out of the
|
||||
Live operator ISOs include these packages to make this path available out of the
|
||||
box:
|
||||
|
||||
```text
|
||||
|
|
@ -102,7 +102,7 @@ Expected outputs:
|
|||
```text
|
||||
target/release/colibri-daemon
|
||||
target/release/colibri
|
||||
target/release/colibri-smoke-agent
|
||||
target/release/colibri-test-agent
|
||||
target/release/colibri-mcp
|
||||
target/release/colibri-tui
|
||||
```
|
||||
|
|
@ -122,7 +122,7 @@ mdo -u root rm -f /var/run/colibri/colibri-daemon-supervisor.pid
|
|||
|
||||
mdo -u root install -m 0555 target/release/colibri-daemon /usr/local/bin/colibri-daemon
|
||||
mdo -u root install -m 0555 target/release/colibri /usr/local/bin/colibri
|
||||
mdo -u root install -m 0555 target/release/colibri-smoke-agent /usr/local/bin/colibri-smoke-agent
|
||||
mdo -u root install -m 0555 target/release/colibri-test-agent /usr/local/bin/colibri-test-agent
|
||||
mdo -u root install -m 0555 target/release/colibri-mcp /usr/local/bin/colibri-mcp
|
||||
mdo -u root install -m 0555 target/release/colibri-tui /usr/local/bin/colibri-tui
|
||||
mdo -u root install -m 0555 packaging/freebsd/colibri_daemon.in /usr/local/etc/rc.d/colibri_daemon
|
||||
|
|
@ -132,9 +132,8 @@ mdo -u root service colibri_daemon start
|
|||
```
|
||||
|
||||
`service colibri_daemon start` should return to the shell after a few seconds. If
|
||||
it stays in the foreground, check that the rc.d script uses
|
||||
`colibri_daemon_binary`, not `colibri_daemon_program`, and that `command=` is
|
||||
`/usr/sbin/daemon`.
|
||||
it does not, stop the command, collect the service file and daemon log, and hand
|
||||
those back through git before continuing.
|
||||
|
||||
## Validate runtime
|
||||
|
||||
|
|
@ -197,20 +196,21 @@ mdo -u root service colibri_daemon restart
|
|||
Sanity checks:
|
||||
|
||||
```sh
|
||||
grep -n 'colibri_daemon_program\|colibri_daemon_binary\|^command=\|^command_args=' /usr/local/etc/rc.d/colibri_daemon
|
||||
sh -n /usr/local/etc/rc.d/colibri_daemon
|
||||
service colibri_daemon status
|
||||
colibri status
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `colibri_daemon_binary` exists.
|
||||
- `command="/usr/sbin/daemon"` exists.
|
||||
- no `colibri_daemon_program` remains.
|
||||
- no `-u ${colibri_daemon_user}` remains in `command_args`.
|
||||
- the rc.d script has valid shell syntax.
|
||||
- `service colibri_daemon start` returns to the shell.
|
||||
- `colibri status` can connect to `/var/run/colibri/colibri.sock`.
|
||||
|
||||
## Future ISO improvement
|
||||
|
||||
Add a helper script, tentatively `/usr/local/bin/colibri-live-rebuild`, that
|
||||
automates this runbook:
|
||||
A future helper script, tentatively `/usr/local/bin/colibri-live-rebuild`, should
|
||||
automate this runbook:
|
||||
|
||||
1. clone/update `/home/clawdie/ai/colibri-build`
|
||||
2. checkout requested branch or commit
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@
|
|||
<li><code>colibri-daemon</code> — agent supervisor, skills catalog, Glasspane state machine</li>
|
||||
<li><code>colibri-tui</code> — live ratatui dashboard (agent states, spawn/kill, sessions)</li>
|
||||
<li><code>colibri-mcp</code> — MCP bridge for Zed, Claude Code, Cursor, and other MCP clients</li>
|
||||
<li><code>colibri-test-agent</code> — local no-network Colibri launch check</li>
|
||||
<li>Firefox browser</li>
|
||||
<li>Tailscale package (needs auth key)</li>
|
||||
<li><code>pi</code> coding agent harness (npm global)</li>
|
||||
|
|
@ -120,6 +121,7 @@ colibri list-tasks # Coordination board
|
|||
colibri list-skills # Skills catalog
|
||||
colibri-mcp tools # MCP bridge, read-only by default
|
||||
COLIBRI_MCP_WRITE=1 colibri-mcp tools # trusted write-capable profile
|
||||
colibri spawn-local /usr/local/bin/colibri-test-agent --session-id local-check
|
||||
colibri create-task --title "check network"
|
||||
colibri list-tasks --status queued</pre>
|
||||
<p>
|
||||
|
|
@ -127,6 +129,24 @@ colibri list-tasks --status queued</pre>
|
|||
<code>/usr/local/share/clawdie-iso/mcp-examples/</code>.
|
||||
</p>
|
||||
|
||||
<h2>LLM provider keys</h2>
|
||||
<p>
|
||||
Colibri can run local checks without a key. Remote providers need a key
|
||||
in <code>/usr/local/etc/colibri/provider.env</code>. Keep this file
|
||||
root-owned and mode <code>0600</code>; it is read when
|
||||
<code>colibri_daemon</code> starts.
|
||||
</p>
|
||||
<pre>
|
||||
mdo -u root cp /usr/local/etc/colibri/provider.env.sample /usr/local/etc/colibri/provider.env
|
||||
mdo -u root chmod 600 /usr/local/etc/colibri/provider.env
|
||||
mdo -u root ee /usr/local/etc/colibri/provider.env
|
||||
mdo -u root service colibri_daemon restart</pre>
|
||||
<p>Put only the providers you use in that file:</p>
|
||||
<pre>
|
||||
DEEPSEEK_API_KEY="sk-..."
|
||||
OPENROUTER_API_KEY="sk-or-..."
|
||||
ANTHROPIC_API_KEY="sk-ant-..."</pre>
|
||||
|
||||
<h2>pi assistant</h2>
|
||||
<pre>
|
||||
pi # interactive session
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ bash
|
|||
zsh
|
||||
ohmyzsh
|
||||
git
|
||||
# Live Colibri rebuild lane: lets the running USB rebuild and redeploy Colibri
|
||||
# without a full ISO rebuild for every small service/runtime iteration.
|
||||
rust
|
||||
pkgconf
|
||||
tailscale
|
||||
avahi-app
|
||||
nss_mdns
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ mkdir -p "${BIN_DIR}" "${RC_DIR}" "${ETC_DIR}" "${NEWSYSLOG_DIR}" "${DB_DIR}" "$
|
|||
|
||||
copy_bin colibri-daemon
|
||||
copy_bin colibri
|
||||
copy_bin colibri-smoke-agent
|
||||
copy_bin colibri-test-agent
|
||||
copy_bin colibri-mcp
|
||||
|
||||
if [ "${COLIBRI_STAGE_INCLUDE_TUI}" != "0" ] && [ -x "${COLIBRI_ARTIFACT_DIR}/colibri-tui" ]; then
|
||||
|
|
@ -71,62 +71,22 @@ install -m 0555 "${RC_SOURCE}" "${RC_DIR}/colibri_daemon"
|
|||
install -m 0644 "${NEWSYSLOG_SOURCE}" "${NEWSYSLOG_DIR}/colibri.conf"
|
||||
|
||||
if ! grep -q '^command="/usr/sbin/daemon"' "${RC_DIR}/colibri_daemon" || \
|
||||
! grep -Eq -- '-o .*colibri_daemon_(program|binary)' "${RC_DIR}/colibri_daemon"; then
|
||||
echo "ERROR: staged colibri_daemon rc.d script does not supervise colibri-daemon with daemon(8)" >&2
|
||||
echo " Update COLIBRI_REPO (${COLIBRI_REPO}) before building; the live USB must not block boot in rc.d." >&2
|
||||
! grep -q -- '-o .*colibri_daemon_binary' "${RC_DIR}/colibri_daemon" || \
|
||||
! grep -q 'colibri_daemon_provider_env' "${RC_DIR}/colibri_daemon" || \
|
||||
! grep -q 'rm -f "${colibri_daemon_socket}" "${pidfile}" "${supervisor_pidfile}"' "${RC_DIR}/colibri_daemon" || \
|
||||
! grep -q 'chmod 644 "${pidfile}"' "${RC_DIR}/colibri_daemon" || \
|
||||
! grep -q 'chmod 660 "${colibri_daemon_socket}"' "${RC_DIR}/colibri_daemon"; then
|
||||
echo "ERROR: staged colibri_daemon rc.d script is missing required live USB supervision hooks" >&2
|
||||
echo " Update COLIBRI_REPO (${COLIBRI_REPO}) before building." >&2
|
||||
exit 66
|
||||
fi
|
||||
|
||||
# Fix procname: the upstream procname="/usr/sbin/daemon" doesn't match
|
||||
# daemon(8)'s process title ("daemon: name[pid] (daemon)"). Match the
|
||||
# first word instead. Since check_pidfile uses the pidfile (PID-scoped),
|
||||
# there's no collision with other daemon(8) instances.
|
||||
sed -i '' 's/^procname="\/usr\/sbin\/daemon"$/procname="daemon:"/' \
|
||||
"${RC_DIR}/colibri_daemon"
|
||||
|
||||
# Fix ${name}_program override: rc.subr line 1120 silently replaces
|
||||
# command= with ${name}_program if set, so colibri_daemon_program=
|
||||
# overrode command="/usr/sbin/daemon" — daemon(8) was never invoked.
|
||||
# Rename the variable so rc.subr leaves command= alone. Newer Colibri sources
|
||||
# may already use colibri_daemon_binary; this replacement is intentionally
|
||||
# harmless when there is no old variable left.
|
||||
sed -i '' 's/colibri_daemon_program/colibri_daemon_binary/g' \
|
||||
"${RC_DIR}/colibri_daemon"
|
||||
|
||||
# Remove -u from daemon(8) args: rc.subr already runs as colibri via su,
|
||||
# so daemon(8)'s own privilege drop double-drops and fails with
|
||||
# "failed to set user environment".
|
||||
sed -i '' 's/ -u \${colibri_daemon_user} //' \
|
||||
"${RC_DIR}/colibri_daemon"
|
||||
|
||||
# Fix pidfile permissions: daemon(8) -P creates the pidfile as 0600
|
||||
# owned by the target user, which blocks non-root users (clawdie) from
|
||||
# running 'service colibri_daemon status'. Chmod in poststart.
|
||||
# Use awk instead of sed append syntax: BSD sed's multi-line append form is
|
||||
# easy to get wrong and can corrupt the rc.d script by appending to every line.
|
||||
# Newer Colibri sources may already carry these chmods; do not duplicate them.
|
||||
if ! grep -q 'chmod 644 "${pidfile}"' "${RC_DIR}/colibri_daemon"; then
|
||||
_rc_tmp="${RC_DIR}/colibri_daemon.tmp"
|
||||
awk '
|
||||
{ print }
|
||||
/socket ready/ {
|
||||
print " chmod 644 \"${pidfile}\" 2>/dev/null || true"
|
||||
print " chmod 660 \"${colibri_daemon_socket}\" 2>/dev/null || true"
|
||||
}
|
||||
' "${RC_DIR}/colibri_daemon" > "${_rc_tmp}"
|
||||
mv "${_rc_tmp}" "${RC_DIR}/colibri_daemon"
|
||||
chmod 0555 "${RC_DIR}/colibri_daemon"
|
||||
if grep -q -- '-u \${colibri_daemon_user}' "${RC_DIR}/colibri_daemon"; then
|
||||
echo "ERROR: staged colibri_daemon rc.d script has unsupported live USB command wiring" >&2
|
||||
echo " Update COLIBRI_REPO (${COLIBRI_REPO}) before building." >&2
|
||||
exit 66
|
||||
fi
|
||||
|
||||
# Add DeepSeek API key and cache warming to daemon environment.
|
||||
# These are injected into the rc.d prestart so the daemon picks them up
|
||||
# without needing a separate config file.
|
||||
sed -i '' '/export COLIBRI_COST_MODE/a\
|
||||
export DEEPSEEK_API_KEY="${DEEPSEEK_API_KEY:-}"\
|
||||
export COLIBRI_CACHE_WARMING="true"\
|
||||
export COLIBRI_CACHE_WARMING_INTERVAL_HOURS="6"' \
|
||||
"${RC_DIR}/colibri_daemon"
|
||||
|
||||
cat > "${ETC_DIR}/rc.conf.sample" <<EOF
|
||||
# Colibri control plane service defaults for the Clawdie ISO.
|
||||
# Merge into /etc/rc.conf or /etc/rc.conf.d/colibri_daemon.
|
||||
|
|
@ -138,10 +98,24 @@ colibri_daemon_run_dir="/var/run/colibri"
|
|||
colibri_daemon_socket="/var/run/colibri/colibri.sock"
|
||||
colibri_daemon_db_path="/var/db/colibri/colibri.sqlite"
|
||||
colibri_daemon_logfile="/var/log/colibri/daemon.log"
|
||||
colibri_daemon_provider_env="/usr/local/etc/colibri/provider.env"
|
||||
colibri_daemon_host="\$(hostname)"
|
||||
colibri_cost_mode="${COLIBRI_COST_MODE}"
|
||||
EOF
|
||||
|
||||
cat > "${ETC_DIR}/provider.env.sample" <<'EOF'
|
||||
# Optional provider keys for colibri_daemon. Copy this file to provider.env,
|
||||
# chmod it 0600, fill in only the providers you use, then restart the service.
|
||||
#
|
||||
# DEEPSEEK_API_KEY="sk-..."
|
||||
# OPENROUTER_API_KEY="sk-or-..."
|
||||
# ANTHROPIC_API_KEY="sk-ant-..."
|
||||
#
|
||||
# Optional endpoints/models:
|
||||
# DEEPSEEK_ENDPOINT="https://api.deepseek.com/chat/completions"
|
||||
# DEEPSEEK_MODEL="deepseek-chat"
|
||||
EOF
|
||||
|
||||
cat > "${ETC_DIR}/README.iso" <<'EOF'
|
||||
Colibri ISO staging notes
|
||||
=========================
|
||||
|
|
@ -149,11 +123,15 @@ Colibri ISO staging notes
|
|||
The ISO build creates the colibri user/group and stages the rc.d service.
|
||||
The colibri-daemon runs under daemon(8) supervision and is enabled at boot.
|
||||
If the daemon fails, it restarts automatically without blocking SDDM/XFCE.
|
||||
Provider keys are optional and live in /usr/local/etc/colibri/provider.env.
|
||||
Keep that file root-owned and mode 0600, then restart colibri_daemon.
|
||||
|
||||
Runtime validation:
|
||||
|
||||
service colibri_daemon start
|
||||
colibri status
|
||||
colibri create-task --title "iso smoke"
|
||||
colibri spawn-local /usr/local/bin/colibri-test-agent --session-id iso-check
|
||||
colibri create-task --title "iso check"
|
||||
colibri list-tasks --status queued
|
||||
colibri-mcp tools
|
||||
COLIBRI_MCP_WRITE=1 colibri-mcp tools # trusted write-capable MCP profile
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue