Added nono profiles & orca integration - Added some extensions to start working on
This commit is contained in:
+313
@@ -0,0 +1,313 @@
|
||||
# Nono profiles
|
||||
|
||||
This repository stores local nono profiles under [`profiles/nono/`](../profiles/nono/). The active nono directory contains one symlink per profile:
|
||||
|
||||
```text
|
||||
~/.config/nono/profiles/pi-local.json
|
||||
-> /srv/data/code/harness-tools/profiles/nono/pi-local.json
|
||||
```
|
||||
|
||||
Keeping the JSON in Git makes profile changes reviewable. The symlink lets nono load the repository copy by profile name.
|
||||
|
||||
## Run Pi with nono
|
||||
|
||||
Launch Pi from the repository you want to edit:
|
||||
|
||||
```bash
|
||||
cd /path/to/project
|
||||
nono run --profile pi-local -- pi
|
||||
```
|
||||
|
||||
`pi-local` gives the launch working directory read/write access. A session that needs several repositories also needs explicit paths in the profile.
|
||||
|
||||
Check which profiles nono can load:
|
||||
|
||||
```bash
|
||||
nono profile list
|
||||
nono profile validate pi-local
|
||||
```
|
||||
|
||||
Inspect a denied operation from inside a sandbox:
|
||||
|
||||
```bash
|
||||
nono why --self --path /resolved/path --op read
|
||||
nono why --self --path /resolved/path --op write
|
||||
nono why --self --path /resolved/path --op readwrite
|
||||
```
|
||||
|
||||
A profile change affects the next sandbox launch. It cannot expand the permissions of the current process.
|
||||
|
||||
## Orca Pi runner routing
|
||||
|
||||
Orca launches Pi through [`scripts/pi-orca.fish`](../scripts/pi-orca.fish). The runner resolves the canonical Git project through [`scripts/orca-nono-profile.py`](../scripts/orca-nono-profile.py), then selects the nono profile from [`profiles/orca/project-nono-profiles.json`](../profiles/orca/project-nono-profiles.json).
|
||||
|
||||
The runner treats the runtime, sandbox, and Pi agent directory as one configuration:
|
||||
|
||||
| Route | Nono profile | Node runtime | Pi agent directory |
|
||||
| --- | --- | --- | --- |
|
||||
| Default | `pi-orca-local` | system Node 26 | `~/.pi/agent` |
|
||||
| `/srv/work` descendants | `pi-work` | fnm Node 22.23.2 | `~/.pi/profiles/cyone` |
|
||||
|
||||
The separate Pi agent directories are required because native extension dependencies such as `better-sqlite3` are compiled for one Node ABI. Never point Node 22 and Node 26 runners at the same `PI_CODING_AGENT_DIR`.
|
||||
|
||||
Exact canonical-project mappings override root mappings. Root mappings use the longest matching ancestor of either the canonical Git root or the actual launch path. This keeps linked worktrees launched below `/srv/work` on the work stack even when their main checkout lives elsewhere, while `/srv/work-other` does not match `/srv/work`.
|
||||
|
||||
```bash
|
||||
orca-nono-profile show /srv/work/code/example
|
||||
orca-nono-profile set pi-work /srv/work/code/example
|
||||
orca-nono-profile unset /srv/work/code/example
|
||||
orca-nono-profile set-root pi-work /srv/work
|
||||
orca-nono-profile unset-root /srv/work
|
||||
```
|
||||
|
||||
After changing a route, Node runtime, or Pi profile, restart the Orca terminal. Existing Pi processes cannot switch runtimes or agent directories. The runner fails closed when its trusted resolver or resolved nono profile is unavailable; it never falls back from a work route to the default Node 26 state.
|
||||
|
||||
## Edit profiles with the skill
|
||||
|
||||
The repository skill lives at [`skills/tools/nono-profiles/`](../skills/tools/nono-profiles/). Pi invokes it when you ask to create or edit a nono profile, change sandbox directories, select an Internet tier, add domains, configure sockets, or troubleshoot profile access.
|
||||
|
||||
Example requests:
|
||||
|
||||
- “Update my nono profile so this session can edit three client repositories.”
|
||||
- “Create a project profile with npm, GitHub, and the staging API allowlisted.”
|
||||
- “Make an offline profile for this repository.”
|
||||
- “Give this profile read-only access to a shared documentation checkout.”
|
||||
|
||||
The skill asks whether to change `pi-local` or create a derived profile. It then collects exact paths, access levels, an Internet tier, and any required domains. It shows the resolved policy and a diff before writing the repository profile.
|
||||
|
||||
The skill stages candidates under `~/.config/nono/profile-drafts/` and validates them in strict mode. It does not edit `~/.config/nono/profiles/` from inside a sandbox. When a new profile needs activation, run the supplied symlink command outside that sandbox.
|
||||
|
||||
## Current `pi-local` baseline
|
||||
|
||||
[`profiles/nono/pi-local.json`](../profiles/nono/pi-local.json) extends the registry-managed `nolabs-ai/pi` profile. It adds:
|
||||
|
||||
- read/write access to the launch working directory and temporary directory
|
||||
- read-only access to local Pi extension source and `$HOME/.bun`; the Orca runner invokes the selected Node executable explicitly rather than relying on `PATH`
|
||||
- pathname-mediated access to the system resolver Unix socket on Linux
|
||||
- an Internet hostname allowlist for model providers, source hosts, package registries, and toolchain downloads
|
||||
|
||||
The parent profile contributes more policy, including Pi state access, security groups, credential route definitions, URL-opening origins, localhost URL opening, and service launching. Inspect the resolved profile before treating a child as narrower than its parent:
|
||||
|
||||
```bash
|
||||
nono profile show pi-local
|
||||
```
|
||||
|
||||
## Profile settings
|
||||
|
||||
### `extends`
|
||||
|
||||
`extends` names one parent profile:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "nolabs-ai/pi"
|
||||
}
|
||||
```
|
||||
|
||||
Inheritance is transitive. List-valued capabilities and included groups are generally additive. An empty child list does not reliably remove a parent capability, so choose a narrower parent when the child needs fewer permissions.
|
||||
|
||||
Use `pi-local` as the parent when its existing filesystem and domain permissions are acceptable. Use `nolabs-ai/pi` when building an offline profile, a smaller domain allowlist, or an open-network profile without inheriting `pi-local`'s hostname list.
|
||||
|
||||
### `meta`
|
||||
|
||||
Give each profile a stable command-line name and a short description:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"name": "pi-client-a",
|
||||
"description": "Pi access for Client A repositories and development services"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Keep the filename aligned with the name: `profiles/nono/pi-client-a.json`.
|
||||
|
||||
### `groups.include`
|
||||
|
||||
`groups.include` adds reusable policy groups defined by built-in or package profiles. Group entries may include platform conditions. Treat groups as capabilities inherited from the parent; an empty list does not remove parent groups.
|
||||
|
||||
### `workdir.access`
|
||||
|
||||
The working directory is the directory where you launch nono, not the directory containing the profile.
|
||||
|
||||
```json
|
||||
{
|
||||
"workdir": {
|
||||
"access": "readwrite"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Launch from the project root when one repository needs write access. Add explicit filesystem entries for additional repositories.
|
||||
|
||||
### Filesystem directories
|
||||
|
||||
Directory fields apply recursively:
|
||||
|
||||
| Field | Access |
|
||||
| --- | --- |
|
||||
| `filesystem.read` | Read-only |
|
||||
| `filesystem.write` | Write-only |
|
||||
| `filesystem.allow` | Read/write |
|
||||
|
||||
A multi-repository profile can enumerate repositories:
|
||||
|
||||
```json
|
||||
{
|
||||
"filesystem": {
|
||||
"allow": [
|
||||
"/srv/data/code/client-a/frontend",
|
||||
"/srv/data/code/client-a/backend"
|
||||
],
|
||||
"read": [
|
||||
"/srv/data/code/shared-docs"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Enumerating repositories limits the profile's reach. Granting `/srv/data/code/client-a` gives the selected access to every current and future child directory, which may suit a dedicated client workspace but carries a larger blast radius.
|
||||
|
||||
Resolve symlinks before adding paths. nono may enforce access against the canonical target.
|
||||
|
||||
### Exact files
|
||||
|
||||
Use exact-file fields when the session needs one file rather than its directory:
|
||||
|
||||
| Field | Access |
|
||||
| --- | --- |
|
||||
| `filesystem.read_file` | Read-only |
|
||||
| `filesystem.write_file` | Write-only |
|
||||
| `filesystem.allow_file` | Read/write |
|
||||
|
||||
### Temporary files
|
||||
|
||||
`$TMPDIR` under `filesystem.allow` permits temporary-file creation. Keep it when tools need scratch files. Remove it only after checking the tools used by that profile.
|
||||
|
||||
### Unix sockets
|
||||
|
||||
`filesystem.unix_socket` lists local socket paths. Socket access is separate from Internet access:
|
||||
|
||||
```json
|
||||
{
|
||||
"filesystem": {
|
||||
"unix_socket": [
|
||||
"/run/systemd/resolve/io.systemd.Resolve"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add exact sockets for required local services. Avoid granting a socket directory.
|
||||
|
||||
`linux.af_unix_mediation: "pathname"` enables pathname-based Unix-socket mediation on Linux.
|
||||
|
||||
### Network access
|
||||
|
||||
`network.block` and `network.allow_domain` define three useful tiers.
|
||||
|
||||
#### Offline
|
||||
|
||||
Derive from `nolabs-ai/pi`, block networking, and clear inherited host-opening capabilities:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "nolabs-ai/pi",
|
||||
"network": {
|
||||
"block": true
|
||||
},
|
||||
"open_urls": {
|
||||
"allow_origins": [],
|
||||
"allow_localhost": false
|
||||
},
|
||||
"allow_launch_services": false
|
||||
}
|
||||
```
|
||||
|
||||
Do not derive this tier from allowlisted `pi-local`. Its inherited proxy domains conflict with blocked networking.
|
||||
|
||||
#### Allowlisted
|
||||
|
||||
Enable networking and list exact hostnames:
|
||||
|
||||
```json
|
||||
{
|
||||
"network": {
|
||||
"block": false,
|
||||
"allow_domain": [
|
||||
"git.example.com",
|
||||
"registry.npmjs.org",
|
||||
"api.staging.example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Entries are hostnames, not full URLs or path patterns. Include artifact hosts and CDNs used by package managers, not only their metadata endpoint. Start with the operations the project performs and add the hosts those operations require.
|
||||
|
||||
A child of `pi-local` inherits its existing domains. Derive from `nolabs-ai/pi` when the project needs a smaller or different list.
|
||||
|
||||
#### Open
|
||||
|
||||
Enable networking without an inherited domain allowlist:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "nolabs-ai/pi",
|
||||
"network": {
|
||||
"block": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Open mode permits destinations beyond the hosts currently known to the project. Review the parent's URL-opening and credential settings separately.
|
||||
|
||||
### URL opening
|
||||
|
||||
`open_urls.allow_origins` lists origins that sandboxed tools may ask the host to open. `open_urls.allow_localhost` controls localhost origins. These settings do not replace `network.allow_domain`.
|
||||
|
||||
The `nolabs-ai/pi` parent grants selected authentication and source-host origins plus localhost. Keep, narrow, or clear them according to the project.
|
||||
|
||||
### Service launching
|
||||
|
||||
`allow_launch_services` controls service launching on supported platforms. Set it to `false` for offline profiles. Review its inherited value for the other network tiers.
|
||||
|
||||
### Credential routes
|
||||
|
||||
Credential routes let nono mediate secrets and restrict upstream endpoints. Network access to a host and access to a credential route are separate permissions. Prefer mediated routes over storing API keys where the sandboxed process can read them.
|
||||
|
||||
Check the installed Pi package guide before enabling a route:
|
||||
|
||||
```text
|
||||
~/.config/nono/packages/nolabs-ai/pi/README.md
|
||||
```
|
||||
|
||||
## Safe change workflow
|
||||
|
||||
1. Create `~/.config/nono/profile-drafts/<name>.json`.
|
||||
2. Validate and inspect the resolved policy:
|
||||
|
||||
```bash
|
||||
nono profile validate --draft <name> --strict
|
||||
nono profile show ~/.config/nono/profile-drafts/<name>.json
|
||||
```
|
||||
|
||||
3. Review the parent, filesystem capabilities, Internet tier, domains, URL-opening origins, service launching, sockets, and credential routes.
|
||||
4. Copy the approved draft to `profiles/nono/<name>.json`.
|
||||
5. Validate the repository copy:
|
||||
|
||||
```bash
|
||||
nono profile validate --strict profiles/nono/<name>.json
|
||||
```
|
||||
|
||||
6. For a new repository-managed profile, create its active symlink outside the sandbox:
|
||||
|
||||
```bash
|
||||
ln -sfn /absolute/repo/profiles/nono/<name>.json ~/.config/nono/profiles/<name>.json
|
||||
nono profile validate <name>
|
||||
```
|
||||
|
||||
7. Start a new nono session with the profile.
|
||||
|
||||
Use `nono profile promote <name>` only when you want a regular active profile instead of a repository symlink. Replacing an existing regular profile requires nono's draft base-hash guard; use nono's edit workflow rather than bypassing that check.
|
||||
Reference in New Issue
Block a user