Compare commits
1 commit
main
...
docs/legac
| Author | SHA1 | Date | |
|---|---|---|---|
| c9684a5dba |
12 changed files with 95 additions and 252 deletions
|
|
@ -10,6 +10,15 @@ Use this skill for the static site generator that builds tenant homes and tenant
|
|||
This skill is also responsible for the transition from the current plain HTML
|
||||
site to the future Astro + Strapi setup in the `cms` jail.
|
||||
|
||||
Legacy public sites still exist outside Astro. In particular:
|
||||
|
||||
- `html/osa/` is the live source for `osa.smilepowered.org`
|
||||
- `html/clawdie/` is still a hand-edited public landing tree
|
||||
|
||||
Do not assume every public HTML change belongs in `bootstrap/cms/*`. If the
|
||||
requested copy already exists under `html/`, edit that source directly unless
|
||||
the task is an explicit migration into Astro.
|
||||
|
||||
## Scope
|
||||
|
||||
This skill covers:
|
||||
|
|
@ -91,6 +100,7 @@ Repo paths:
|
|||
- Landing source: `bootstrap/cms/clawdie-si/`
|
||||
- Docs source: `bootstrap/cms/clawdie-docs/`
|
||||
- Public docs source of truth: `docs/public/`
|
||||
- Legacy OSA landing source: `html/osa/`
|
||||
|
||||
Inside the `cms` jail:
|
||||
|
||||
|
|
|
|||
|
|
@ -341,8 +341,8 @@ clawdie-iso/
|
|||
Derived from `setup/environment.ts` host baseline + desktop-installer + DE packages:
|
||||
|
||||
**Clawdie host baseline:**
|
||||
`node24`, `npm`, `bsddialog`, `bastille`, `git`, `tmux`, `python312`, `uv`,
|
||||
`ripgrep`, `fd-find`, `rsync`, `postgresql18-client`, `dejavu`
|
||||
`node24`, `npm`, `bsddialog`, `bastille`, `git`, `tmux`, `python311`, `uv`,
|
||||
`ripgrep`, `fd-find`, `rsync`, `postgresql18-client`, `py311-pillow`, `dejavu`
|
||||
|
||||
**Xorg baseline:**
|
||||
`xorg-minimal`, `xf86-video-intel`, `drm-kmod`,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ See [docs/public/architecture/warden.md](docs/public/architecture/warden.md).
|
|||
git clone https://codeberg.org/Clawdie/Clawdie-AI.git /home/clawdie/clawdie-ai
|
||||
cd /home/clawdie/clawdie-ai
|
||||
|
||||
pkg install node24 npm git python312 uv rsync
|
||||
pkg install node24 npm git python312 py312-uv rsync
|
||||
npm install
|
||||
npm install -g @earendil-works/pi-coding-agent
|
||||
# If setup.sh did not launch onboarding automatically:
|
||||
|
|
@ -102,14 +102,12 @@ The current FreeBSD deployment depends on:
|
|||
### `controlplane`
|
||||
|
||||
Role:
|
||||
|
||||
- main Clawdie control-plane jail
|
||||
- Telegram intake
|
||||
- scheduling
|
||||
- Warden task dispatch
|
||||
|
||||
Profile:
|
||||
|
||||
- `freebsd-jail`
|
||||
- `thick`
|
||||
- `vnet`
|
||||
|
|
@ -118,12 +116,10 @@ Profile:
|
|||
### `db`
|
||||
|
||||
Role:
|
||||
|
||||
- PostgreSQL memory backend
|
||||
- persistent service
|
||||
|
||||
Profile:
|
||||
|
||||
- `freebsd-jail`
|
||||
- `thick`
|
||||
- `vnet`
|
||||
|
|
@ -138,23 +134,19 @@ Profile:
|
|||
## Snapshot Policy
|
||||
|
||||
Manual milestone snapshots:
|
||||
|
||||
- human-named
|
||||
- day-first
|
||||
- month abbreviation
|
||||
|
||||
Examples:
|
||||
|
||||
- `@postgres18-ready-08.mar.2026`
|
||||
- `@fresh-08.mar.2026`
|
||||
|
||||
Automatic snapshots:
|
||||
|
||||
- handled by Sanoid
|
||||
- keep Sanoid's internal `autosnap_...` naming
|
||||
|
||||
Current automated Sanoid targets:
|
||||
|
||||
- `zroot/clawdie-runtime/jails/db`
|
||||
- `zroot/clawdie-runtime/jails/controlplane`
|
||||
|
||||
|
|
|
|||
17
README.md
17
README.md
|
|
@ -155,12 +155,12 @@ just setup-cms # npm run setup -- --step cms
|
|||
- Internet access for `pkg` and `npm`
|
||||
- `bash` and `git` available before first run
|
||||
- **`just`** — command runner (`pkg install just` on FreeBSD; preinstalled on Clawdie ISO)
|
||||
- **At least one agent CLI on `PATH`**: one of `pi`, `aider`, `claude`, `codex`, or `gemini`. The controlplane harness uses Aider+Pi as the primary driver. Onboarding fails fast if none are present (see [`doc/AGENT-CLI-VALIDATION.md`](doc/AGENT-CLI-VALIDATION.md) for the validated install paths). The Clawdie ISO ships claude/gemini/pi via the npm-globals bundle, provisions Aider in a Python 3.12 venv, and includes codex via `pkg install codex`.
|
||||
- **At least one agent CLI on `PATH`**: one of `pi`, `aider`, `claude`, `codex`, or `gemini`. The controlplane harness uses Aider+Pi as the primary driver. Onboarding fails fast if none are present (see [`doc/AGENT-CLI-VALIDATION.md`](doc/AGENT-CLI-VALIDATION.md) for the validated install paths). The Clawdie ISO ships claude/gemini/pi via the npm-globals bundle, aider via `py311-aider_chat` pkg, and codex via `pkg install codex`.
|
||||
|
||||
Recommended explicit host baseline before first run:
|
||||
|
||||
```sh
|
||||
sudo pkg install -y bash git bastille node24 npm tmux btop python312 uv ripgrep fd-find rsync postgresql18-client dejavu edk2-bhyve just
|
||||
sudo pkg install -y bash git bastille node24 npm tmux btop python311 uv ripgrep fd-find rsync postgresql18-client py311-pillow dejavu py311-aider_chat edk2-bhyve just
|
||||
```
|
||||
|
||||
The `edk2-bhyve` package provides UEFI firmware required for optional browser-vm support
|
||||
|
|
@ -169,16 +169,15 @@ The `edk2-bhyve` package provides UEFI firmware required for optional browser-vm
|
|||
On FreeBSD, use `fd-find`. It provides the `fd` command that `pi` expects and
|
||||
avoids colliding with the unrelated `fd` file manager package.
|
||||
|
||||
Python package-flavored extras stay out of the baseline until the FreeBSD
|
||||
quarterly repository publishes Python 3.12 flavors. Install Aider/Pillow-style
|
||||
tools into explicit Python 3.12 venvs when needed.
|
||||
The host baseline also includes `py311-pillow` and `dejavu` so tmux screenshot
|
||||
capture works without a separate `uv pip install Pillow` step.
|
||||
|
||||
If the host still has multiple Python minors installed, pin `uv` to 3.12
|
||||
If the host still has both Python 3.11 and 3.12 installed, pin `uv` to 3.11
|
||||
explicitly until the generic `python3` path is cleaned up:
|
||||
|
||||
```sh
|
||||
uv venv --python 3.12
|
||||
uv run --python 3.12 <command>
|
||||
uv venv --python 3.11
|
||||
uv run --python 3.11 <command>
|
||||
```
|
||||
|
||||
### Operator Glasspane
|
||||
|
|
@ -216,7 +215,7 @@ First use:
|
|||
|
||||
```bash
|
||||
# 1. Install the recommended FreeBSD host baseline
|
||||
sudo pkg install -y bash git bastille node24 npm tmux btop python312 uv ripgrep fd-find rsync postgresql18-client dejavu just
|
||||
sudo pkg install -y bash git bastille node24 npm tmux btop python311 uv ripgrep fd-find rsync postgresql18-client py311-pillow dejavu py311-aider_chat just
|
||||
|
||||
# 2. Clone the repository
|
||||
git clone https://codeberg.org/Clawdie/Clawdie-AI.git /home/clawdie/clawdie-ai
|
||||
|
|
|
|||
|
|
@ -30,22 +30,26 @@ export PATH=/opt/clawdie/cargo/bin:$PATH
|
|||
|
||||
## Working install (tested)
|
||||
|
||||
1. Create a project-local Python 3.12 venv. The FreeBSD quarterly repo still
|
||||
publishes only older Python-flavored Aider packages, so keep Aider out of the
|
||||
host pkg baseline and install it into a venv:
|
||||
1) Install Aider from packages (adds many deps but works):
|
||||
|
||||
```sh
|
||||
python3.12 -m venv /home/clawdie/clawdie-ai/tmp/aider-venv
|
||||
sudo pkg install py311-aider_chat
|
||||
```
|
||||
|
||||
2. Upgrade Aider + pin litellm to the expected version inside the venv:
|
||||
2) Create a project-local venv that can override litellm:
|
||||
|
||||
```sh
|
||||
python3.11 -m venv --system-site-packages /home/clawdie/clawdie-ai/tmp/aider-venv
|
||||
```
|
||||
|
||||
3) Upgrade Aider + pin litellm to the expected version inside the venv:
|
||||
|
||||
```sh
|
||||
/home/clawdie/clawdie-ai/tmp/aider-venv/bin/pip install --no-user --no-deps --upgrade --ignore-installed aider-chat==0.86.2
|
||||
/home/clawdie/clawdie-ai/tmp/aider-venv/bin/pip install --no-user --no-deps --upgrade --ignore-installed litellm==1.81.10
|
||||
```
|
||||
|
||||
3. Align tree-sitter with the system tree-sitter-languages package (fixes repo-map crash):
|
||||
4) Align tree-sitter with the system tree-sitter-languages package (fixes repo-map crash):
|
||||
|
||||
```sh
|
||||
env TMPDIR=/home/clawdie/clawdie-ai/tmp \
|
||||
|
|
@ -59,7 +63,7 @@ FreeBSD ships `tree_sitter_languages` from packages (1.10.2) which expects
|
|||
TypeError: __init__() takes exactly 1 argument (2 given)
|
||||
```
|
||||
|
||||
4. Run Aider (use the venv binary):
|
||||
4) Run Aider (use the venv binary):
|
||||
|
||||
```sh
|
||||
env AIDER_ANALYTICS_DISABLE=1 /home/clawdie/clawdie-ai/tmp/aider-venv/bin/aider \
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
# Vaultwarden Connectivity — domedog Findings (2026-06-19, updated)
|
||||
|
||||
**Host:** domedog (`domedog.pro`, Linux)
|
||||
**Agent:** Claude
|
||||
**PRs under evaluation:** clawdie-iso #65 (merged as #67) + clawdie-ai #14 (doc contract)
|
||||
|
||||
## Test results — end-to-end PASS ✅
|
||||
|
||||
Full chain proven: bootstrap creds → `bw` login → unlock → fetch → `.env` → re-lock.
|
||||
|
||||
| Step | Command | Result |
|
||||
| ---------------- | --------------------------------------------------------- | --------------------------------------------------- |
|
||||
| Server reachable | `curl -sI https://vault.smilepowered.org/` | ✅ HTTP 200 (Rocket/Vaultwarden) |
|
||||
| bw CLI installed | `bw --version` | ✅ 2026.5.0 |
|
||||
| API key login | `bw login --apikey` (via `BW_CLIENTID`/`BW_CLIENTSECRET`) | ✅ Logged in as `samo.blatnik@gmail.com` |
|
||||
| Vault unlock | `bw unlock --passwordenv BW_PASSWORD` | ✅ Unlock succeeds — master password is correct |
|
||||
| Fetch item | `clawdie-vault-fetch --keys DEEPSEEK_API_KEY` | ✅ Resolved 1 of 1 key |
|
||||
| Write to `.env` | `--write-env /tmp/smoke.env` | ✅ Written 0600, value correct (35 chars, `sk-...`) |
|
||||
| Re-lock on exit | trap cleanup | ✅ Vault re-locked automatically |
|
||||
|
||||
## The test item
|
||||
|
||||
A `DEEPSEEK_API_KEY` login item was created in the `agent-secrets` collection,
|
||||
with the **item name = the env var name** and the **value in the password
|
||||
field**, per the documented contract. The helper fetched it cleanly with
|
||||
`bw get password DEEPSEEK_API_KEY` — confirming the name-based retrieval
|
||||
contract works.
|
||||
|
||||
## One real bug found and fixed
|
||||
|
||||
**`clawdie-vault-fetch` failed when `bw` was already logged in.**
|
||||
|
||||
`bw config server "$SERVER"` refuses with `Logout required before server config
|
||||
update` when the CLI is already authenticated. The helper treated that as fatal
|
||||
(`exit 1`), which broke **every repeat run** on a host that is already logged in
|
||||
— including the very case the helper exists for (refresh `.env` from the vault
|
||||
on demand).
|
||||
|
||||
The `bw login` block already tolerated the analogous "already logged in" case.
|
||||
Fix (clawdie-iso, branch `fix/vault-fetch-bw-config-when-logged-in`): mirror
|
||||
that pattern for `bw config` — capture stderr/stdout and tolerate
|
||||
`logout required` / `already configured` / `already set`, failing only on a
|
||||
real error. Verified: the fixed helper runs cleanly from the logged-in state
|
||||
(previously exited 1 at the config step).
|
||||
|
||||
## Correction to the earlier draft
|
||||
|
||||
An earlier draft of this doc reported `bw unlock` failing with
|
||||
`Decryption failed` and concluded the master password was wrong. That was
|
||||
incorrect: the unlock failure was a side effect of running the flow against a
|
||||
**stale logged-in session**. After `bw logout` and a clean re-run, unlock
|
||||
succeeds with the **same** master password — it was never wrong. The only
|
||||
defect was the `bw config` intolerance documented above.
|
||||
|
||||
## Setup state on domedog
|
||||
|
||||
- `bw` 2026.5.0 installed at `~/.nvm/versions/node/v22.22.0/bin/bw`.
|
||||
- Helper staged at `~/.colibri/clawdie-vault-fetch` (the fixed version).
|
||||
- Bootstrap env at `~/.config/vault-bootstrap.env` (0600) — `BW_CLIENTID`,
|
||||
`BW_CLIENTSECRET`, and `BW_PASSWORD` all correct and verified by a successful
|
||||
fetch.
|
||||
- Server set to `https://vault.smilepowered.org`.
|
||||
|
||||
## Not wired yet (documented follow-ups)
|
||||
|
||||
- **Runtime consumption:** the helper fetches into a `.env`, but nothing yet
|
||||
loads that `.env` into a running agent's environment at launch. This is the
|
||||
next milestone (soul load + harness launch).
|
||||
- **Auto-refresh:** no scheduled/firstboot caller of the helper yet — it is run
|
||||
manually. The `bw config` bug fix is a prerequisite for auto-refresh to be
|
||||
reliable.
|
||||
|
||||
## PR #65 / #14 assessment
|
||||
|
||||
**Code quality:** solid. `clawdie-vault-fetch` has trap-based lock-on-exit,
|
||||
headless `--apikey` login, tolerates "already logged in", sensible exit codes
|
||||
(0/1/3/4), and a `--write-env` upsert that preserves untouched keys at 0600.
|
||||
The one repeat-run bug (`bw config` intolerance) is fixed in a follow-up.
|
||||
|
||||
**No blockers** to the runtime-consumption milestone. The secret→`.env` path is
|
||||
proven; what remains is having an agent read it.
|
||||
|
|
@ -1,25 +1,10 @@
|
|||
# Vaultwarden Setup for Agents
|
||||
|
||||
Secrets store: `vault.smilepowered.org` (Vaultwarden, self-hosted).
|
||||
Organization: **Clawdie**.
|
||||
Collection: `agent-secrets` (where agents' secrets are organized).
|
||||
Secrets store: `vault.smilepowered.org` (Vaultwarden, self-hosted).
|
||||
Organization: **Clawdie** (39727691-3403-4c50-89b8-d5f24310e79c).
|
||||
Collection: `agent-secrets` (94ba61b8-633c-454e-b749-f115617eeac3).
|
||||
|
||||
Agents retrieve secrets programmatically via the `clawdie-vault-fetch` helper or
|
||||
the `bw` CLI — no passwords in chat.
|
||||
|
||||
## Retrieval contract (important)
|
||||
|
||||
Every secret is stored as **one login item whose ITEM NAME is exactly the env
|
||||
var name** (e.g. `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`), with the **value in
|
||||
the password field**. This is what `clawdie-vault-fetch` depends on:
|
||||
|
||||
- `bw get password <ITEM-NAME>` returns the value raw — no `jq` needed.
|
||||
- Fetch is **fail-closed on ambiguity**: if two visible items share a name, the
|
||||
fetch errors out instead of guessing. **Item names must therefore be unique**
|
||||
across the agent account's visible vault (not just within `agent-secrets`), so
|
||||
do not reuse a name in a personal collection.
|
||||
- The helper does **not** scope by collection ID. The `agent-secrets` collection
|
||||
is for operator organization; uniqueness is enforced at fetch time by name.
|
||||
Agents use the `bw` CLI to retrieve secrets programmatically — no passwords in chat.
|
||||
|
||||
> **Note:** `bw` CLI only accepts **personal** API keys (from Account Settings).
|
||||
> Organization API keys are for the REST API, not the CLI. Do not use them here.
|
||||
|
|
@ -39,13 +24,11 @@ access Vaultwarden, but those credentials can't be stored in Vaultwarden itself
|
|||
as the only copy.
|
||||
|
||||
**Operator's role:**
|
||||
|
||||
1. Create a Vaultwarden user account for the agent.
|
||||
2. Invite the user to the Clawdie organization with access to `agent-secrets`.
|
||||
3. Share the master password via a secure channel (file drop, not chat).
|
||||
|
||||
**Agent's role:**
|
||||
|
||||
1. Generate personal API key: Account Settings → Security → Keys → View API Key.
|
||||
2. Write `BW_CLIENTID` (starts with `user.`), `BW_CLIENTSECRET`, and
|
||||
`BW_PASSWORD` to a 0600 bootstrap file: `~/.config/vault-bootstrap.env`.
|
||||
|
|
@ -61,35 +44,30 @@ operator must create the user account and deliver the master password out-of-ban
|
|||
|
||||
## Verification Test
|
||||
|
||||
After onboarding, verify with this smoke test — run from the agent host. The
|
||||
helper does the login/unlock/lock lifecycle and exits non-zero on failure.
|
||||
|
||||
```sh
|
||||
# 1. Preferred: use the helper end-to-end. It reads
|
||||
# ~/.config/vault-bootstrap.env (0600) and prints KEY=VALUE lines for every
|
||||
# key it resolved. Exit 3 = no bootstrap file (skip); 1 = broken; 4 = no bw.
|
||||
clawdie-vault-fetch
|
||||
|
||||
# 2. Resolve one specific key and write it into .env (0600, upsert):
|
||||
clawdie-vault-fetch --write-env ~/.env --keys "OPENROUTER_API_KEY"
|
||||
```
|
||||
|
||||
If at least one `KEY=VALUE` line prints, onboarding is complete — the helper
|
||||
locks the vault on exit. To verify the raw `bw` path instead (e.g. the helper is
|
||||
not installed yet):
|
||||
After onboarding, verify with this smoke test — run from the agent host:
|
||||
|
||||
```sh
|
||||
# 1. Load bootstrap env without echoing secrets.
|
||||
set -a
|
||||
. ~/.config/vault-bootstrap.env
|
||||
set +a
|
||||
|
||||
# 2. Configure, login, unlock, and capture a raw session token.
|
||||
bw config server https://vault.smilepowered.org
|
||||
bw login --apikey
|
||||
BW_SESSION="$(bw unlock --raw --passwordenv BW_PASSWORD)"
|
||||
bw get password OPENROUTER_API_KEY --session "$BW_SESSION" # prints the value
|
||||
bw lock
|
||||
export BW_SESSION
|
||||
|
||||
# 3. List items in agent-secrets collection.
|
||||
bw list items --session "$BW_SESSION" --collectionid 94ba61b8-633c-454e-b749-f115617eeac3 >/dev/null
|
||||
|
||||
# 4. Retrieve the hermes-debby Forgejo username.
|
||||
bw list items --session "$BW_SESSION" --search "hermes-debby" | jq -r '.[0].login.username'
|
||||
|
||||
# Expected output: hermes-debby
|
||||
```
|
||||
|
||||
If the value resolves: Vaultwarden onboarding complete.
|
||||
If the username resolves: Vaultwarden onboarding complete. Lock the vault (`bw lock`).
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -110,7 +88,6 @@ bw config server https://vault.smilepowered.org
|
|||
|
||||
Generate your personal API key: Account Settings → Security → Keys → View API Key.
|
||||
You'll receive:
|
||||
|
||||
- `BW_CLIENTID` (starts with `user.`)
|
||||
- `BW_CLIENTSECRET`
|
||||
|
||||
|
|
@ -143,18 +120,10 @@ bw unlock --passwordenv BW_PASSWORD
|
|||
|
||||
### 5. Retrieve a secret
|
||||
|
||||
Fetch by item **name** (the env var name); the value lives in the password
|
||||
field. This is the same path `clawdie-vault-fetch` uses:
|
||||
|
||||
```sh
|
||||
bw get password OPENROUTER_API_KEY --session "$BW_SESSION"
|
||||
```
|
||||
|
||||
To upsert resolved secrets into your `.env` without copy-paste, prefer the
|
||||
helper:
|
||||
|
||||
```sh
|
||||
clawdie-vault-fetch --write-env ~/.env
|
||||
bw list items --session "$BW_SESSION" --search "hermes-debby" | jq '.[0].login'
|
||||
# or get by ID
|
||||
bw get item <item-id> --session "$BW_SESSION"
|
||||
```
|
||||
|
||||
### 6. Lock when done
|
||||
|
|
@ -163,64 +132,10 @@ clawdie-vault-fetch --write-env ~/.env
|
|||
bw lock
|
||||
```
|
||||
|
||||
## Runtime fetch: `clawdie-vault-fetch`
|
||||
|
||||
The manual flow above is the operator/agent CLI path. For a host to pull its own
|
||||
provider keys **out of the box**, the image ships a small language-neutral
|
||||
helper, `clawdie-vault-fetch` (`/usr/local/bin/`), that the post-install setup
|
||||
flow shells out to and the live USB can run directly. It depends only on `bw` —
|
||||
no node module, no `jq`.
|
||||
|
||||
### Item-naming convention (the contract)
|
||||
|
||||
For a secret to be auto-fetchable, store it in `agent-secrets` as a **login item
|
||||
whose name is exactly the env var name**, with the value in the **password
|
||||
field**:
|
||||
|
||||
| Item name | Field | Becomes |
|
||||
| -------------------- | -------- | ---------------------- |
|
||||
| `ANTHROPIC_API_KEY` | password | `ANTHROPIC_API_KEY=…` |
|
||||
| `OPENAI_API_KEY` | password | `OPENAI_API_KEY=…` |
|
||||
| `OPENROUTER_API_KEY` | password | `OPENROUTER_API_KEY=…` |
|
||||
| `ZAI_API_KEY` | password | `ZAI_API_KEY=…` |
|
||||
|
||||
The default key set mirrors clawdie-ai's `PROVIDER_KEY_BY_PROVIDER` (anthropic,
|
||||
openai, openrouter, zai, deepseek, gemini, groq). `bw get password <NAME>`
|
||||
returns the raw value, so no JSON parsing is involved.
|
||||
|
||||
### Bootstrap drop (the one secret that can't live in the vault)
|
||||
|
||||
The helper reads `~/.config/vault-bootstrap.env` (mode 0600) for the headless
|
||||
credentials — exactly the file from the [Bootstrap Flow](#bootstrap-flow) above:
|
||||
|
||||
```sh
|
||||
BW_CLIENTID=user....
|
||||
BW_CLIENTSECRET=...
|
||||
BW_PASSWORD=<master-password>
|
||||
```
|
||||
|
||||
**No bootstrap file → the helper exits cleanly and does nothing**, so a host with
|
||||
no vault access still uses the manual setup wizard. That is the floor; the vault
|
||||
fetch only ever adds.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
clawdie-vault-fetch # print KEY=VALUE lines to stdout
|
||||
clawdie-vault-fetch --write-env FILE # upsert results into FILE (0600), keys preserved
|
||||
clawdie-vault-fetch --bootstrap FILE # explicit bootstrap env file
|
||||
clawdie-vault-fetch --keys "A B C" # override the key-name list
|
||||
```
|
||||
|
||||
Exit codes let a caller tell "skip" from "broken": `0` ran cleanly · `1` vault
|
||||
configured but login/unlock/fetch failed · `3` no bootstrap config (fall back to
|
||||
manual) · `4` `bw` not installed. The helper always `bw lock`s on exit and never
|
||||
logs secret values.
|
||||
|
||||
## Current items in agent-secrets
|
||||
|
||||
| Name | Type | Purpose |
|
||||
| -------------------- | ----- | -------------------------------------------------------- |
|
||||
| Name | Type | Purpose |
|
||||
|------|------|---------|
|
||||
| hermes-debby Forgejo | login | Hermes's code.smilepowered.org password (browser access) |
|
||||
|
||||
## Rules
|
||||
|
|
|
|||
|
|
@ -9,24 +9,19 @@ tmux
|
|||
btop
|
||||
bsddialog
|
||||
codex
|
||||
# python3 is 3.11 (FreeBSD PYTHON_DEFAULT); python312 available as python3.12.
|
||||
python311
|
||||
python312
|
||||
uv
|
||||
ripgrep
|
||||
fd-find
|
||||
rsync
|
||||
postgresql18-client
|
||||
dnsmasq
|
||||
# hermes runtime: ffmpeg (media + voice-transcription), py311-pillow (Pillow
|
||||
# core dep; venvs use --system-site-packages so the system pkg satisfies it).
|
||||
ffmpeg
|
||||
py311-pillow
|
||||
dejavu
|
||||
rust
|
||||
|
||||
# Controlplane harness helpers. Aider is installed into a venv until the
|
||||
# quarterly FreeBSD repo publishes a Python 3.12 package flavor.
|
||||
# Controlplane harness (Aider + Pi multi-agent orchestrator)
|
||||
py311-aider_chat
|
||||
just
|
||||
|
||||
# Wayland display stack — used by worker jails (cage) and operator sessions
|
||||
|
|
|
|||
7
setup.sh
7
setup.sh
|
|
@ -71,8 +71,8 @@ install_host_pkg_baseline() {
|
|||
tmux)
|
||||
command -v tmux >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
;;
|
||||
python312)
|
||||
command -v python3.12 >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
python311)
|
||||
command -v python3 >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
;;
|
||||
uv)
|
||||
command -v uv >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
|
|
@ -92,6 +92,9 @@ install_host_pkg_baseline() {
|
|||
rust)
|
||||
command -v rustc >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
;;
|
||||
py311-pillow)
|
||||
python3 -c "import PIL" >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
;;
|
||||
dejavu)
|
||||
[ -f /usr/local/share/fonts/dejavu/DejaVuSansMono.ttf ] || missing_pkgs+=("$pkg")
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export class NoAgentCliError extends Error {
|
|||
[
|
||||
'No agent CLI found on PATH.',
|
||||
'Clawdie needs pi and aider for the Aider+Pi controlplane harness.',
|
||||
'Install via the ISO bundle or: npm install -g @earendil-works/pi-coding-agent; install Aider in a Python 3.12 venv if needed.',
|
||||
'Install via the ISO bundle or: pkg install py311-aider_chat, npm install -g @earendil-works/pi-coding-agent.',
|
||||
'Alternative CLIs (claude, codex, gemini) are also accepted.',
|
||||
].join(' '),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const HOST_PREREQUISITE_CHECKS: Record<
|
|||
dnsmasq: { key: 'DNSMASQ', check: () => commandExists('dnsmasq') },
|
||||
tmux: { key: 'TMUX', check: () => commandExists('tmux') },
|
||||
btop: { key: 'BTOP', check: () => commandExists('btop') },
|
||||
python312: { key: 'PYTHON3', check: () => commandExists('python3.12') },
|
||||
python311: { key: 'PYTHON3', check: () => commandExists('python3') },
|
||||
uv: { key: 'UV', check: () => commandExists('uv') },
|
||||
ripgrep: { key: 'RIPGREP', check: () => commandExists('rg') },
|
||||
'fd-find': { key: 'FD', check: () => commandExists('fd') },
|
||||
|
|
@ -60,8 +60,20 @@ const HOST_PREREQUISITE_CHECKS: Record<
|
|||
tailscale: { key: 'TAILSCALE', check: () => commandExists('tailscale') },
|
||||
just: { key: 'JUST', check: () => commandExists('just') },
|
||||
rust: { key: 'RUST', check: () => commandExists('rustc') },
|
||||
'py311-aider_chat': { key: 'AIDER', check: () => commandExists('aider') },
|
||||
node24: { key: 'NODE', check: () => commandExists('node') },
|
||||
npm: { key: 'NPM', check: () => commandExists('npm') },
|
||||
'py311-pillow': {
|
||||
key: 'PILLOW',
|
||||
check: () => {
|
||||
try {
|
||||
execSync('python3 -c "import PIL"', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
dejavu: {
|
||||
key: 'DEJAVU_FONT',
|
||||
check: () =>
|
||||
|
|
@ -99,9 +111,11 @@ export async function run(_args: string[]): Promise<void> {
|
|||
const service = commandExists('service');
|
||||
const sudo = commandExists('sudo');
|
||||
const jailConf = fs.existsSync('/etc/jail.conf');
|
||||
const hasPython311 = commandExists('python3.11');
|
||||
const hasPython312 = commandExists('python3.12');
|
||||
const python3Version = commandVersion('python3');
|
||||
const python3NeedsPinning = hasPython312 && !python3Version.includes('3.12');
|
||||
const python3NeedsPinning =
|
||||
hasPython311 && hasPython312 && python3Version.includes('3.12');
|
||||
|
||||
// Check for pi binary (path from env or default 'pi')
|
||||
const piBin = PI_TUI_BIN;
|
||||
|
|
@ -243,6 +257,7 @@ export async function run(_args: string[]): Promise<void> {
|
|||
const psql = getPrereq('PSQL');
|
||||
const node = getPrereq('NODE');
|
||||
const npm = getPrereq('NPM');
|
||||
const pillow = getPrereq('PILLOW');
|
||||
const dejavuFont = getPrereq('DEJAVU_FONT');
|
||||
const seatd = getPrereq('SEATD');
|
||||
const weston = getPrereq('WESTON');
|
||||
|
|
@ -307,11 +322,13 @@ export async function run(_args: string[]): Promise<void> {
|
|||
psql: psql.present,
|
||||
node: node.present,
|
||||
npm: npm.present,
|
||||
pillow: pillow.present,
|
||||
dejavuFont: dejavuFont.present,
|
||||
seatd: seatd.present,
|
||||
cage: cage.present,
|
||||
weston: weston.present,
|
||||
vmBhyve: vmBhyve.present,
|
||||
hasPython311,
|
||||
hasPython312,
|
||||
python3Version,
|
||||
python3NeedsPinning,
|
||||
|
|
@ -332,7 +349,7 @@ export async function run(_args: string[]): Promise<void> {
|
|||
{
|
||||
python3Version,
|
||||
},
|
||||
'Python 3.12 is installed but python3 is not pinned to 3.12; use an explicit python3.12/uv pin for setup commands.',
|
||||
'Multiple Python versions detected. Pin uv to Python 3.11 until python3 is repointed to 3.11.',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -364,11 +381,12 @@ export async function run(_args: string[]): Promise<void> {
|
|||
PYTHON3: python3.present,
|
||||
PYTHON3_STATUS: python3.status,
|
||||
PYTHON3_INSTALL_CMD: python3.installCmd,
|
||||
PYTHON311: hasPython311,
|
||||
PYTHON312: hasPython312,
|
||||
PYTHON3_VERSION: python3Version || 'unknown',
|
||||
UV_PYTHON_PIN_REQUIRED: python3NeedsPinning,
|
||||
UV_PYTHON_HINT: python3NeedsPinning
|
||||
? 'uv venv --python 3.12 && uv run --python 3.12 <command>'
|
||||
? 'uv venv --python 3.11 && uv run --python 3.11 <command>'
|
||||
: 'not_required',
|
||||
NODE: node.present,
|
||||
NODE_STATUS: node.status,
|
||||
|
|
@ -391,6 +409,9 @@ export async function run(_args: string[]): Promise<void> {
|
|||
PSQL: psql.present,
|
||||
PSQL_STATUS: psql.status,
|
||||
PSQL_INSTALL_CMD: psql.installCmd,
|
||||
PILLOW: pillow.present,
|
||||
PILLOW_STATUS: pillow.status,
|
||||
PILLOW_INSTALL_CMD: pillow.installCmd,
|
||||
DEJAVU_FONT: dejavuFont.present,
|
||||
DEJAVU_FONT_STATUS: dejavuFont.status,
|
||||
DEJAVU_FONT_INSTALL_CMD: dejavuFont.installCmd,
|
||||
|
|
|
|||
|
|
@ -408,21 +408,12 @@ function printStep(
|
|||
}
|
||||
|
||||
function hasPiAuthProvider(provider: string): boolean {
|
||||
const authFile = path.join(
|
||||
process.env.HOME || '',
|
||||
'.pi',
|
||||
'agent',
|
||||
'auth.json',
|
||||
);
|
||||
const authFile = path.join(process.env.HOME || '', '.pi', 'agent', 'auth.json');
|
||||
try {
|
||||
const parsed = JSON.parse(fs.readFileSync(authFile, 'utf-8')) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const parsed = JSON.parse(fs.readFileSync(authFile, 'utf-8')) as Record<string, unknown>;
|
||||
const entry = parsed?.[provider];
|
||||
if (typeof entry === 'string') return entry.trim().length > 0;
|
||||
if (entry && typeof entry === 'object')
|
||||
return Object.keys(entry).length > 0;
|
||||
if (entry && typeof entry === 'object') return Object.keys(entry).length > 0;
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
|
|
@ -469,12 +460,8 @@ function printLlmStatus(envFile: string): void {
|
|||
console.log(
|
||||
`\n ${COLS.warn}No LLM provider auth found. Configure one after install and restart:${COLS.reset}`,
|
||||
);
|
||||
console.log(
|
||||
` ${COLS.skipped} Recommended: run pi, then /login and select ChatGPT Plus/Pro (Codex).${COLS.reset}`,
|
||||
);
|
||||
console.log(
|
||||
` ${COLS.skipped} Or add an API key such as ANTHROPIC_API_KEY=sk-ant-...${COLS.reset}`,
|
||||
);
|
||||
console.log(` ${COLS.skipped} Recommended: run pi, then /login and select ChatGPT Plus/Pro (Codex).${COLS.reset}`);
|
||||
console.log(` ${COLS.skipped} Or add an API key such as ANTHROPIC_API_KEY=sk-ant-...${COLS.reset}`);
|
||||
console.log(
|
||||
` ${COLS.skipped} sudo service ${SERVICE_NAME} restart${COLS.reset}`,
|
||||
);
|
||||
|
|
@ -522,7 +509,7 @@ function printAiderTip(): void {
|
|||
);
|
||||
if (!hasAider) {
|
||||
console.log(
|
||||
` install: ${COLS.skipped}python3.12 -m venv /opt/clawdie/venv/aider && /opt/clawdie/venv/aider/bin/pip install aider-chat${COLS.reset}`,
|
||||
` install: ${COLS.skipped}pkg install -y py311-aider_chat${COLS.reset}`,
|
||||
);
|
||||
}
|
||||
console.log(` docs : ${COLS.skipped}https://aider.chat/docs/${COLS.reset}`);
|
||||
|
|
@ -583,9 +570,7 @@ export async function run(argv: string[]): Promise<void> {
|
|||
const opts = parseArgs(argv);
|
||||
const projectRoot = process.cwd();
|
||||
const envFile = path.join(projectRoot, '.env');
|
||||
const envContent = fs.existsSync(envFile)
|
||||
? fs.readFileSync(envFile, 'utf-8')
|
||||
: '';
|
||||
const envContent = fs.existsSync(envFile) ? fs.readFileSync(envFile, 'utf-8') : '';
|
||||
|
||||
if (getPlatform() !== 'freebsd') {
|
||||
console.error('install orchestrator is FreeBSD only.');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue