528 lines
20 KiB
Markdown
528 lines
20 KiB
Markdown
# harness-tools
|
|
|
|
Personal [Pi](https://github.com/earendil-works/pi-mono) extensions, skills, global agent instructions, sandbox profiles, and supporting services.
|
|
|
|
## What this repository installs
|
|
|
|
[`config/pi-links.json`](config/pi-links.json) is the source of truth for the normal installation. The link manager exposes:
|
|
|
|
- global agent instructions for Pi, Codex, and Claude;
|
|
- 34 shared skills under `~/.agents/skills/`;
|
|
- the `manage-pi-links` and `nono-profiles` project-only skills under `.pi/skills/`;
|
|
- five global Pi extensions under `~/.pi/agent/extensions/`:
|
|
- **dictate**: local Linux voice dictation;
|
|
- **effort-controls**: `/effort` reasoning selection and `/fast` priority mode;
|
|
- **pi-workflow**: persisted, gated feature workflows;
|
|
- **prompt-snippets**: per-message prompt rule toggles;
|
|
- **update**: `/update` and `--update` support.
|
|
|
|
The repository also contains `copy-all`, `file-search`, and `subagents` extensions, but the normal manifest does not install them globally. The `pptx`, `stop-slop`, `subagents`, and `xlsx` skills are also intentionally excluded. Archived resources under `__archived/` are never installed. Update `config/pi-links.json` deliberately if that policy changes.
|
|
|
|
## Fresh-machine setup
|
|
|
|
The commands below reproduce the normal setup. They assume Linux, a systemd user session, and the current canonical checkout path. Pi and the shared skills work on other platforms, but the nono launcher and Dictate sections are Linux-specific.
|
|
|
|
### 1. Install the base tools
|
|
|
|
Required:
|
|
|
|
- Git with access to `git.jb.codes`;
|
|
- Node.js 22.19 or newer with npm;
|
|
- Pi Coding Agent;
|
|
- a configured model provider.
|
|
|
|
Install Pi using its official npm package:
|
|
|
|
```bash
|
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
|
pi --version
|
|
```
|
|
|
|
A Bun global install also works, but record its executable path later when configuring `pi-sbx`.
|
|
|
|
Start Pi once and authenticate with a subscription or API-key provider:
|
|
|
|
```bash
|
|
pi
|
|
```
|
|
|
|
Run `/login` inside Pi. Pi stores its user state under `${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}`. When Pi runs through nono, prefer nono credential routes so real API keys do not enter the sandbox; see [Sandboxed Pi credentials](#sandboxed-pi-credentials).
|
|
|
|
### 2. Clone the repository
|
|
|
|
Several current profiles and instruction imports contain `/srv/data/code/harness-tools`, so using that path requires no repository edits:
|
|
|
|
```bash
|
|
if [ ! -e /srv/data/code ]; then
|
|
sudo install -d -o "$USER" -g "$(id -gn)" /srv/data/code
|
|
fi
|
|
test -d /srv/data/code && test -w /srv/data/code || {
|
|
echo '/srv/data/code already exists but is not a writable directory' >&2
|
|
exit 1
|
|
}
|
|
|
|
git clone ssh://git@git.jb.codes:7722/jb/harness-tools.git \
|
|
/srv/data/code/harness-tools
|
|
cd /srv/data/code/harness-tools
|
|
```
|
|
|
|
The setup creates `/srv/data/code` only when absent. If it already exists, keep its current ownership and obtain access through the machine's normal administration policy.
|
|
|
|
If the checkout lives elsewhere, replace the machine-specific paths before syncing:
|
|
|
|
- `docs/global.CLAUDE.md`;
|
|
- `profiles/nono/pi-local.json`;
|
|
- `profiles/nono/pi-orca-local.json`;
|
|
- `profiles/nono/pi-work.json`;
|
|
- the copied `~/.config/pi-sbx/config.json` described below.
|
|
|
|
Dictate currently targets `/run/user/1000/pi-dictate.sock` in both the extension and profile. It therefore expects UID 1000. Change and review the socket path before installation if `id -u` reports another UID.
|
|
|
|
### 3. Install repository dependencies
|
|
|
|
The linked TypeScript extensions resolve runtime dependencies from this checkout, so `node_modules` is required even though the extensions have no build step:
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
npm ci
|
|
npm run typecheck
|
|
```
|
|
|
|
Use `npm ci` after pulling a lockfile change. Node.js must satisfy the version in [`package.json`](package.json).
|
|
|
|
### 4. Install instructions, skills, and extensions
|
|
|
|
Preview the exact changes first, then apply them:
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
./scripts/pi-links.mjs sync --dry-run
|
|
./scripts/pi-links.mjs sync
|
|
./scripts/pi-links.mjs check
|
|
```
|
|
|
|
A successful check currently reports 44 links and zero local package entries. The manager:
|
|
|
|
- preserves unrelated global resources;
|
|
- refuses to overwrite regular files, directories, or links owned outside this repository;
|
|
- uses absolute links for global resources and relative links for project-only skills.
|
|
|
|
Resolve any reported collision manually instead of deleting it blindly. Run `/reload` in an active Pi session, or restart Pi, after the sync.
|
|
|
|
Do not also run `pi install /path/to/harness-tools` for the normal setup. That installs the root as a Pi package and applies the broader `package.json` resource globs, which is different from the curated `config/pi-links.json` policy and can duplicate resources. It remains useful for a temporary package-development test in an isolated Pi agent directory.
|
|
|
|
### 5. Verify Pi
|
|
|
|
```bash
|
|
pi
|
|
```
|
|
|
|
Inside Pi:
|
|
|
|
1. Run `/reload`.
|
|
2. Confirm `/effort`, `/snippets`, `/update`, and `/workflow` are available.
|
|
3. Ask Pi to list its available skills and confirm a shared skill such as `tdd` appears.
|
|
4. From this repository, confirm the project-only `manage-pi-links` and `nono-profiles` skills appear.
|
|
|
|
## Additional Pi packages from Gitea
|
|
|
|
Two extensions are maintained in separate Gitea repositories rather than `harness-tools`. Install them as Pi-managed Git packages after completing the canonical link sync above. Pi clones each package into its agent directory and installs its package dependencies.
|
|
|
|
Run these commands from a normal host terminal. A restrictive nono session may intentionally lack the SSH key or agent socket needed to clone private repositories.
|
|
|
|
### Verify Gitea SSH access
|
|
|
|
Both repositories use SSH on port 7722. Confirm access without changing either checkout:
|
|
|
|
```bash
|
|
GIT_TERMINAL_PROMPT=0 git ls-remote \
|
|
ssh://git@git.jb.codes:7722/jb/pi-interactive-subagents.git HEAD
|
|
GIT_TERMINAL_PROMPT=0 git ls-remote \
|
|
ssh://git@git.jb.codes:7722/jb/pi-todo-herdr.git HEAD
|
|
```
|
|
|
|
Each command should print a commit hash and `HEAD`. Configure the machine's SSH key and `git.jb.codes` host key before continuing if either command fails.
|
|
|
|
### Install both packages
|
|
|
|
```bash
|
|
pi install ssh://git@git.jb.codes:7722/jb/pi-interactive-subagents.git
|
|
pi install ssh://git@git.jb.codes:7722/jb/pi-todo-herdr.git
|
|
pi list
|
|
```
|
|
|
|
Confirm both Gitea URLs appear under `User packages`, then restart Pi or run `/reload`. These package entries are independent of `config/pi-links.json`, so `./scripts/pi-links.mjs check` still reports zero local package entries.
|
|
|
|
Do not globally enable `harness-tools/extensions/subagents` at the same time as `pi-interactive-subagents`. They provide overlapping subagent tools. The curated harness-tools manifest leaves its in-repository implementation disabled for this reason.
|
|
|
|
### Configure interactive subagents
|
|
|
|
[`pi-interactive-subagents`](https://git.jb.codes/jb/pi-interactive-subagents) creates asynchronous child Pi sessions in Herdr tabs or tmux panes. It requires one terminal backend:
|
|
|
|
- **Herdr:** install its Pi integration, then launch Pi inside a Herdr-managed pane;
|
|
- **tmux:** launch Pi inside tmux when Herdr is unavailable.
|
|
|
|
For Herdr:
|
|
|
|
```bash
|
|
herdr integration install pi
|
|
herdr integration status
|
|
herdr
|
|
```
|
|
|
|
Start Pi in a Herdr pane. The extension detects `HERDR_ENV=1` and opens each subagent in an unfocused tab. The `pi-local` nono profile already declares the reviewed Herdr socket used on the original machine; update that machine-specific path if necessary.
|
|
|
|
For tmux:
|
|
|
|
```bash
|
|
tmux new -A -s pi 'pi'
|
|
```
|
|
|
|
The package bundles `scout`, `researcher`, and `worker` agent definitions. Their configured provider, model, thinking level, and tool allowlist live in the package's `agents/` directory. Authenticate the configured provider and confirm the named model is available. To override a bundled definition without editing Pi's managed Git clone, create a same-named file in `${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/agents/` or a trusted project's `.pi/agents/`; project definitions take precedence over global definitions, which take precedence over package definitions.
|
|
|
|
Inside Pi, verify and try the extension:
|
|
|
|
1. Run `/reload`.
|
|
2. Ask Pi to call `subagents_list`.
|
|
3. Confirm `scout`, `researcher`, and `worker` are listed.
|
|
4. Run `/subagent scout Summarize this repository` from a disposable test checkout.
|
|
5. Confirm a Herdr tab or tmux pane opens and the completed result returns to the parent session.
|
|
|
|
The status widget is enabled by the package's example configuration when no local `config.json` exists. Copy and edit `config.json.example` beside the installed package only when a status override is needed. Treat Pi's managed Git checkout as disposable because package updates may reset it; prefer global or project agent overrides for durable customization.
|
|
|
|
### Configure Pi Todo Herdr
|
|
|
|
[`pi-todo-herdr`](https://git.jb.codes/jb/pi-todo-herdr) provides the `set_tasks`, `update_task`, `rm_task`, `list_task`, and `get_task` tools plus a session-local Pi task widget. Herdr is optional for the tools and widget.
|
|
|
|
Inside Pi after `/reload`:
|
|
|
|
1. Confirm the five task tools are available.
|
|
2. Run `/todo` to toggle the widget.
|
|
3. Ask Pi to create a small three-step test plan, update one task, and list the tree.
|
|
|
|
For Herdr sidebar task metadata, back up and edit the existing configuration:
|
|
|
|
```bash
|
|
cp -a ~/.config/herdr/config.toml \
|
|
~/.config/herdr/config.toml.before-pi-todo-herdr
|
|
"${EDITOR:-vi}" ~/.config/herdr/config.toml
|
|
```
|
|
|
|
If `[ui.sidebar.agents]` already exists, edit its existing `rows` value and add `"$task_progress"`, `"$task"`, and `"$task_count"` where desired. Do not add a duplicate TOML table header. If the table does not exist, append the complete block:
|
|
|
|
```toml
|
|
[ui.sidebar.agents]
|
|
rows = [["state_icon", "workspace", "tab"], ["$ask", "$ask_count"], ["$task_progress", "$task", "$task_count"]]
|
|
```
|
|
|
|
Apply and verify the change:
|
|
|
|
```bash
|
|
herdr server reload-config
|
|
herdr status client
|
|
```
|
|
|
|
### Update or remove the Gitea packages
|
|
|
|
Use the same source strings stored by Pi:
|
|
|
|
```bash
|
|
pi update ssh://git@git.jb.codes:7722/jb/pi-interactive-subagents.git
|
|
pi update ssh://git@git.jb.codes:7722/jb/pi-todo-herdr.git
|
|
```
|
|
|
|
Remove them with:
|
|
|
|
```bash
|
|
pi remove ssh://git@git.jb.codes:7722/jb/pi-interactive-subagents.git
|
|
pi remove ssh://git@git.jb.codes:7722/jb/pi-todo-herdr.git
|
|
```
|
|
|
|
Run `/reload` after an update or removal.
|
|
|
|
### Optional development checkouts
|
|
|
|
A Pi-managed package clone is enough for normal use. For source development, use separate durable checkouts so Pi package updates cannot discard work:
|
|
|
|
```bash
|
|
mkdir -p /srv/data/repo-store
|
|
git clone ssh://git@git.jb.codes:7722/jb/pi-interactive-subagents.git \
|
|
/srv/data/repo-store/pi-interactive-subagents
|
|
git clone ssh://git@git.jb.codes:7722/jb/pi-todo-herdr.git \
|
|
/srv/data/repo-store/pi-todo-herdr
|
|
|
|
npm ci --prefix /srv/data/repo-store/pi-interactive-subagents
|
|
npm test --prefix /srv/data/repo-store/pi-interactive-subagents
|
|
npm ci --prefix /srv/data/repo-store/pi-todo-herdr
|
|
npm run typecheck --prefix /srv/data/repo-store/pi-todo-herdr
|
|
npm test --prefix /srv/data/repo-store/pi-todo-herdr
|
|
```
|
|
|
|
Both repositories are separate projects. Keep their changes and releases out of the `harness-tools` checkout.
|
|
|
|
## Companion tools used by installed skills
|
|
|
|
The link sync installs skill instructions, not every external program those skills may call. Install the companion tools you intend to use.
|
|
|
|
### OpenSrc for dependency research
|
|
|
|
`code-research` and `package-source` require the `opensrc` CLI and intentionally use `/srv/data/opensrc` as the single source cache:
|
|
|
|
```bash
|
|
npm install -g --prefix "$HOME/.local" opensrc
|
|
if [ ! -e /srv/data/opensrc ]; then
|
|
sudo install -d -o "$USER" -g "$(id -gn)" /srv/data/opensrc
|
|
fi
|
|
test -d /srv/data/opensrc && test -w /srv/data/opensrc || {
|
|
echo '/srv/data/opensrc already exists but is not a writable directory' >&2
|
|
exit 1
|
|
}
|
|
|
|
if [ ! -e "$HOME/.opensrc" ] && [ ! -L "$HOME/.opensrc" ]; then
|
|
ln -s /srv/data/opensrc "$HOME/.opensrc"
|
|
fi
|
|
|
|
command -v opensrc
|
|
readlink -f "$HOME/.opensrc"
|
|
```
|
|
|
|
The setup preserves existing directory ownership and any existing `~/.opensrc`. If that path already exists, inspect it instead of replacing it. Completion requires it to resolve to `/srv/data/opensrc`.
|
|
|
|
If `~/.opensrc` already exists, inspect it instead of replacing it. Completion requires it to resolve to `/srv/data/opensrc`.
|
|
|
|
### Browser Harness
|
|
|
|
The `browser-harness` skill requires `uv`, Chrome or Chromium, and the Browser Harness CLI:
|
|
|
|
```bash
|
|
uv tool install --python 3.12 --upgrade --force browser-harness
|
|
browser-harness --doctor
|
|
browser-harness <<'PY'
|
|
print(page_info())
|
|
PY
|
|
```
|
|
|
|
For a Browser Use cloud session, authenticate separately with `browser-harness auth login`. Local browser control does not require a cloud key.
|
|
|
|
### Artifact presentation
|
|
|
|
The `artifact-presenter` skill uses [Herdr](https://herdr.dev) and [mcat](https://github.com/Skardyy/mcat). Install both and verify:
|
|
|
|
```bash
|
|
command -v herdr
|
|
command -v mcat
|
|
herdr --version
|
|
mcat --version
|
|
```
|
|
|
|
On Arch-based systems, mcat is available as the `mcat-bin` AUR package. Follow Herdr's installation guide for its CLI. The skill falls back to reporting the artifact path when either program is unavailable.
|
|
|
|
### PDF work
|
|
|
|
The `pdf` skill calls tools as needed rather than maintaining a repository environment. For its common workflows, install the relevant subset of:
|
|
|
|
- Python packages: `pypdf`, `pdfplumber`, `reportlab`, `pymupdf`, `pytesseract`, and `pdf2image`;
|
|
- system tools: Poppler (`pdftotext`, `pdfimages`, and `pdftoppm`), `qpdf`, and Tesseract OCR.
|
|
|
|
The intentionally excluded `pptx` and `xlsx` skills have additional office and rendering dependencies and are not part of the normal setup.
|
|
|
|
## Optional Linux sandbox setup
|
|
|
|
The repository-managed [nono](https://github.com/always-further/nono) profiles and `pi-sbx` launcher are optional, but they reproduce the normal restricted Pi runtime.
|
|
|
|
### Install nono and its Pi package
|
|
|
|
Install the `nono` CLI using its upstream instructions, then pull the parent Pi profile:
|
|
|
|
```bash
|
|
nono pull nolabs-ai/pi
|
|
nono profile show nolabs-ai/pi
|
|
```
|
|
|
|
### Link the repository profiles
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
mkdir -p ~/.config/nono/profiles
|
|
|
|
for profile in pi-local pi-orca-local pi-harness-tools pi-work; do
|
|
source="$PWD/profiles/nono/$profile.json"
|
|
destination="$HOME/.config/nono/profiles/$profile.json"
|
|
if [ -L "$destination" ] && \
|
|
[ "$(readlink -f "$destination")" = "$(readlink -f "$source")" ]; then
|
|
continue
|
|
fi
|
|
if [ -e "$destination" ] || [ -L "$destination" ]; then
|
|
echo "Refusing to replace existing profile: $destination" >&2
|
|
exit 1
|
|
fi
|
|
ln -s "$source" "$destination"
|
|
done
|
|
|
|
for profile in pi-local pi-orca-local pi-harness-tools pi-work; do
|
|
nono profile validate "$profile"
|
|
done
|
|
```
|
|
|
|
The loop is rerunnable for links already targeting this checkout and refuses every other collision.
|
|
|
|
These profiles inherit from one another, so install and validate all four even if only `pi-local` is used initially. Review their filesystem paths, Orca integration paths, socket grants, network allowlist, and work-specific Git path on every new machine.
|
|
|
|
### Install the routed launcher
|
|
|
|
`pi-sbx` is a Fish script. Install Fish, then link the launch commands and systemd slice:
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
mkdir -p ~/.local/bin ~/.config/pi-sbx ~/.config/systemd/user
|
|
|
|
safe_link() {
|
|
source="$1"
|
|
destination="$2"
|
|
if [ -L "$destination" ] && \
|
|
[ "$(readlink -f "$destination")" = "$(readlink -f "$source")" ]; then
|
|
return 0
|
|
fi
|
|
if [ -e "$destination" ] || [ -L "$destination" ]; then
|
|
echo "Refusing to replace existing path: $destination" >&2
|
|
return 1
|
|
fi
|
|
ln -s "$source" "$destination"
|
|
}
|
|
|
|
safe_link "$PWD/scripts/pi-sbx.fish" "$HOME/.local/bin/pi-sbx"
|
|
safe_link "$PWD/scripts/pi-sbx-profile.py" "$HOME/.local/bin/pi-sbx-profile"
|
|
safe_link "$PWD/scripts/pi-orca.fish" "$HOME/.local/bin/pi-orca"
|
|
safe_link "$PWD/scripts/orca-nono-profile.py" "$HOME/.local/bin/orca-nono-profile"
|
|
safe_link "$PWD/systemd/user/pi-agents.slice" \
|
|
"$HOME/.config/systemd/user/pi-agents.slice"
|
|
|
|
if [ ! -e "$HOME/.config/pi-sbx/config.json" ]; then
|
|
cp "$PWD/config/pi-sbx.example.json" "$HOME/.config/pi-sbx/config.json"
|
|
chmod 600 "$HOME/.config/pi-sbx/config.json"
|
|
else
|
|
echo 'Keeping existing ~/.config/pi-sbx/config.json'
|
|
fi
|
|
systemctl --user daemon-reload
|
|
```
|
|
|
|
The setup preserves an existing launcher, systemd unit, or routing configuration unless it already links to this checkout. Resolve reported collisions manually after inspecting both paths.
|
|
|
|
Edit `~/.config/pi-sbx/config.json` before launching. Set:
|
|
|
|
- `nodeExecutable` to `readlink -f "$(command -v node)"`;
|
|
- `piExecutable` to the real Pi executable path;
|
|
- `piAgentDirectory` to the matching Pi state directory;
|
|
- directory routes to paths that exist on this machine;
|
|
- profile-specific runtimes only when a different Node ABI or Pi state directory is intentional.
|
|
|
|
The checked-in example contains paths from the original machine and is a template, not a portable final configuration. Separate Pi agent directories are required when profiles use incompatible Node ABIs with native dependencies.
|
|
|
|
Verify and launch:
|
|
|
|
```bash
|
|
pi-sbx-profile list
|
|
pi-sbx-profile show
|
|
pi-sbx-profile set pi-local /path/to/a/project
|
|
pi-sbx-profile resolve /path/to/a/project
|
|
pi-sbx
|
|
```
|
|
|
|
See [`docs/nono.md`](docs/nono.md) for routing behavior, multi-repository grants, Internet tiers, profile editing, and troubleshooting denials.
|
|
|
|
### Sandboxed Pi credentials
|
|
|
|
The base `nolabs-ai/pi` package supports mediated credential routes. Store secrets in the OS keychain or another nono-supported secret source, then enable only the required route names in a reviewed child profile. For example, supported built-in route names include `openai`, `anthropic`, `gemini`, `github`, and `gitlab`.
|
|
|
|
Do not place real provider keys in files readable by sandboxed Pi if the goal is credential mediation. Consult the installed package guide after `nono pull`:
|
|
|
|
```text
|
|
~/.config/nono/packages/nolabs-ai/pi/README.md
|
|
```
|
|
|
|
## Optional Dictate service
|
|
|
|
Dictate is Linux-only and requires:
|
|
|
|
- PipeWire with `pw-record`;
|
|
- systemd user services;
|
|
- an NVIDIA GPU with a working CUDA runtime;
|
|
- `uv`;
|
|
- network access for the initial locked dependency and model download;
|
|
- UID 1000 unless the hardcoded socket path is changed first.
|
|
|
|
Install the host service from the repository root:
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
./services/dictate/install.sh
|
|
systemctl --user status pi-dictate.socket pi-dictate.service
|
|
```
|
|
|
|
The installer provisions the locked Python environment, verifies the pinned model, installs host-owned systemd units, and enables socket activation. Initial storage is several gigabytes. To reuse an existing model archive or preview the operation:
|
|
|
|
```bash
|
|
./services/dictate/install.sh --model-source /path/to/parakeet-tdt-0.6b-v3.nemo
|
|
./services/dictate/install.sh --dry-run --model-source /path/to/model.nemo
|
|
```
|
|
|
|
Restart a sandboxed Pi after profile or socket changes. In Pi, press `Alt+M` to start or stop dictation and `Alt+N` to cancel. See [`extensions/dictate/README.md`](extensions/dictate/README.md) for privacy, dictionary, model, and troubleshooting details.
|
|
|
|
## Maintenance
|
|
|
|
After pulling repository changes:
|
|
|
|
```bash
|
|
cd /srv/data/code/harness-tools
|
|
git pull --rebase
|
|
npm ci
|
|
./scripts/pi-links.mjs sync --dry-run
|
|
./scripts/pi-links.mjs sync
|
|
./scripts/pi-links.mjs check
|
|
npm run typecheck
|
|
```
|
|
|
|
Run `/reload` after skill, extension, instruction, or separately installed Gitea package changes. Re-run `./services/dictate/install.sh` when Dictate's host service or protocol changes.
|
|
|
|
Before removing repository-managed exposure, preview exactly what will be deleted:
|
|
|
|
```bash
|
|
./scripts/pi-links.mjs prune --dry-run
|
|
```
|
|
|
|
Only run `./scripts/pi-links.mjs prune` after reviewing every removal. The manager prunes repository-owned exposure and leaves unrelated global resources alone.
|
|
|
|
## Development and checks
|
|
|
|
Extensions are TypeScript modules loaded directly by Pi; no build step is required.
|
|
|
|
```bash
|
|
npm ci
|
|
npm run typecheck
|
|
npm test
|
|
```
|
|
|
|
For a one-off extension development run:
|
|
|
|
```bash
|
|
pi -e ./extensions/effort-controls
|
|
pi -e ./extensions/update
|
|
```
|
|
|
|
## Repository layout
|
|
|
|
```text
|
|
config/ Installation and launcher manifests
|
|
docs/ Usage guides, plans, and ADRs
|
|
extensions/ Pi extensions
|
|
profiles/nono/ Repository-managed nono profiles
|
|
scripts/ Link manager and sandbox launch helpers
|
|
services/ Host-side services used by extensions
|
|
skills/ Pi skills, one SKILL.md per skill
|
|
systemd/user/ Repository-managed systemd user units
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|