anon-pi 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile.pi CHANGED
@@ -1,14 +1,19 @@
1
1
  # A minimal image with `pi` (the Earendil Works coding agent) on PATH, for use as
2
- # anon-pi's ANON_PI_IMAGE. It follows the official upstream containerization
3
- # pattern (earendil-works/pi, packages/coding-agent/docs/containerization.md):
4
- # node:24-bookworm-slim + the official `@earendil-works/pi-coding-agent` npm
5
- # package, plus the handful of tools pi's built-in bash/grep/find expect.
2
+ # anon-pi's ANON_PI_IMAGE. node:24-bookworm-slim + the official
3
+ # `@earendil-works/pi-coding-agent` npm package + the tools pi's built-in
4
+ # bash/grep/find expect.
6
5
  #
7
- # Note: unlike the upstream `Dockerfile.pi`, this image sets NO ENTRYPOINT and
8
- # NO config volume. anon-pi passes `pi` as the run command and copies just its
9
- # models.json into this image's ~/.pi/agent at start, so the image just needs
10
- # `pi` reachable on PATH. Anything else you want in the anon session (extensions,
11
- # skills, and their services) belongs HERE, in the image.
6
+ # HOW anon-pi USES THIS IMAGE (stateful model):
7
+ # anon-pi mounts a PERSISTENT per-workdir host dir at the container's
8
+ # ~/.pi/agent, so pi's sessions/history/settings and any extensions you
9
+ # `pi install` persist across launches. On a FRESH home, anon-pi seeds it once
10
+ # from this image's STAGING dir (/opt/anon-pi-seed/agent) + your imported
11
+ # models.json, then stamps a marker and never overwrites again.
12
+ #
13
+ # So image defaults (extensions, trust.json) go in the STAGING dir, NOT in
14
+ # ~/.pi/agent (which is the mount and would be shadowed). Set
15
+ # PI_CODING_AGENT_DIR to the staging dir while running `pi install` so the
16
+ # extension is recorded there.
12
17
  #
13
18
  # Build (pin a digest for reproducibility once pushed to a registry):
14
19
  # podman build -t localhost/anon-pi-pi:latest -f Dockerfile.pi .
@@ -22,20 +27,25 @@ RUN apt-get update \
22
27
  # The official pi coding agent CLI (puts `pi` on PATH).
23
28
  RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
24
29
 
30
+ # The staging dir anon-pi promotes into a fresh home on first launch.
31
+ ENV ANON_PI_STAGE=/opt/anon-pi-seed/agent
32
+ RUN mkdir -p "$ANON_PI_STAGE"
33
+
34
+ # Trust /work so pi does not prompt on the mounted project (staged, so it lands
35
+ # in the persistent home on first launch; anon-pi never writes this for you).
36
+ RUN printf '{"/work": true}\n' > "$ANON_PI_STAGE/trust.json"
37
+
25
38
  # --- Optional: extensions + skills (the capability layer) -------------------
26
- # Install extensions with `pi install` (it records them in settings), NOT a
27
- # global npm install. Uncomment what you want in the anon persona:
39
+ # Install into the STAGING dir (PI_CODING_AGENT_DIR), so `pi install` records the
40
+ # extension there and anon-pi promotes it into the persistent home on first
41
+ # launch. After that you can `pi install` more from inside the session and it
42
+ # persists. Uncomment what you want in the anon persona:
28
43
  #
29
- # RUN pi install npm:pi-subagents
30
- # RUN pi install npm:pi-plan-mode
44
+ # RUN PI_CODING_AGENT_DIR="$ANON_PI_STAGE" pi install npm:pi-subagents
45
+ # RUN PI_CODING_AGENT_DIR="$ANON_PI_STAGE" pi install npm:pi-plan-mode
31
46
  #
32
47
  # An extension that needs a running SERVICE (e.g. pi-webveil + a local SearXNG)
33
48
  # installs and configures that service in the image too. See the worked example
34
- # examples/Dockerfile.pi-webveil (SearXNG over a Unix socket, started by an
35
- # entrypoint that then execs anon-pi's command).
36
- #
37
- # Trust /work up front so pi does not prompt on every run (anon-pi never writes
38
- # this for you):
39
- # RUN mkdir -p /root/.pi/agent && printf '{"/work": true}\n' > /root/.pi/agent/trust.json
49
+ # examples/Dockerfile.pi-webveil.
40
50
 
41
51
  WORKDIR /work
package/README.md CHANGED
@@ -45,18 +45,37 @@ You land in pi, inside the jail, cwd `/work` = `./recon`. pi's web/tool egress i
45
45
  | --- | --- | --- | --- |
46
46
  | `ANON_PI_IMAGE` | for run | | container image with `pi` on `PATH` |
47
47
  | `ANON_PI_LLM` | yes | | RFC1918/link-local `IP[:port]` of the local model (the one direct hole) |
48
- | `ANON_PI_PROXY` | no | `socks5h://127.0.0.1:9050` | the socks5h proxy |
48
+ | `ANON_PI_PROXY` | yes | | the socks5h proxy (Tor/wireproxy/ssh -D). No default: it is what anonymizes |
49
+ | `ANON_PI_EPHEMERAL` | no | (off) | set to `1` for a throwaway, non-persistent session |
49
50
  | `ANON_PI_HOME` | no | `$XDG_CONFIG_HOME/anon-pi` or `~/.config/anon-pi` | anon-pi home |
50
- | `ANON_PI_CONFIG` | no | `<ANON_PI_HOME>/agent` | the seed dir (holds `models.json`) |
51
+ | `ANON_PI_CONFIG` | no | `<ANON_PI_HOME>/agent` | canonical seed dir (holds the imported `models.json`) |
51
52
  | `ANON_PI_SOURCE_MODELS` | no | `~/.pi/agent/models.json` | (`import`) the host `models.json` to read from |
52
53
 
53
54
  ## How it works
54
55
 
55
- 1. **Seed = just `models.json`.** `anon-pi import` writes one file, `<ANON_PI_CONFIG>/models.json`, containing only the provider that serves your local model (see [Generating the seed](#generating-the-seed-anon-pi-import)). No auth for other providers, no sessions, no identity.
56
- 2. **Mount read-only + copy in.** anon-pi mounts the seed read-only at `/anon-pi-seed` and, at start, **copies** `models.json` into the container's own `~/.pi/agent`. It does **not** mount over pi's config dir, so anything the image installed there (pi itself, extensions, skills) survives; the copy just adds your local model to it.
57
- 3. **Run.** anon-pi execs `netcage run --proxy <proxy> --allow-direct <ANON_PI_LLM> -it -v <workdir> -v <seed>:/anon-pi-seed:ro <image> sh -c 'cp /anon-pi-seed/models.json ~/.pi/agent/ && exec pi'`.
56
+ **Stateful by default.** anon-pi mounts a persistent per-workdir host dir at the container's `~/.pi/agent`, so pi's **sessions, history, settings (your model choice), and any extensions you `pi install`** all persist across launches. Re-running in the same folder resumes it. The state dir is `<ANON_PI_HOME>/state/<workdir>/agent`, named with pi's own readable path convention (e.g. `--home-me-proj--`), not a hash, so you can see which folder it belongs to and delete it to reset.
58
57
 
59
- pi has no default model set in the seed, so on start it auto-selects the first available model, your local one (it needs no real API key). Everything that runs, and everything that identifies you, lives in the **image**, not the seed (see below).
58
+ 1. **Mount the persistent home.** `-v <ANON_PI_HOME>/state/<workdir>/agent:/root/.pi/agent`. Everything pi writes there survives.
59
+ 2. **First-launch seed (only when the home is fresh).** anon-pi mounts the image's staged defaults and your imported `models.json`, and the container promotes them into the fresh home, then stamps a `.anon-pi-seed` marker. On later launches the marker is present, so nothing is re-copied and **your changes (added models, installed extensions) are never clobbered**.
60
+ 3. **Run.** `netcage run --proxy <proxy> --allow-direct <ANON_PI_LLM> -it -v <workdir> -v <state>:/root/.pi/agent [-v <models.json>:...:ro] <image> sh -c '<seed-if-fresh> && exec pi'`.
61
+
62
+ pi auto-selects the first available model (your local one; it needs no real API key), so no default needs to be set. Services and default extensions live in the **image**; your state lives in the persistent home.
63
+
64
+ ### Ephemeral (throwaway) sessions
65
+
66
+ For a clean, no-local-trace session, pass `--ephemeral` (or `ANON_PI_EPHEMERAL=1`): anon-pi mounts **no writable state** at all. pi writes to the container's own filesystem, which netcage runs with `--rm`, so it is destroyed when the container exits. Nothing writable ever touches a host path (only the read-only `models.json` seed is mounted), there is no cleanup step, and nothing is left behind even if anon-pi is killed.
67
+
68
+ ```sh
69
+ anon-pi --ephemeral ./scratch
70
+ ```
71
+
72
+ ### Reset a session
73
+
74
+ Delete its state home; the next launch re-seeds:
75
+
76
+ ```sh
77
+ rm -rf ~/.config/anon-pi/state/<workdir-slug>/agent
78
+ ```
60
79
 
61
80
  ## Providing a pi image
62
81
 
@@ -95,30 +114,30 @@ RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
95
114
  WORKDIR /work
96
115
  ```
97
116
 
98
- Because anon-pi copies `models.json` **into** the image's own `~/.pi/agent` rather than replacing it, extensions installed in the image stay active in the anon session.
117
+ Install image defaults into the **staging dir** (`PI_CODING_AGENT_DIR=/opt/anon-pi-seed/agent pi install ...`), NOT `~/.pi/agent`: anon-pi mounts a persistent home over `~/.pi/agent`, and promotes the staging dir into it on a fresh launch. Anything you then `pi install` *inside* a session also persists (it is written to the mounted home). See the `Dockerfile.pi` comments for the exact `pi install` form.
99
118
 
100
- A worked example ships in this package: [`examples/Dockerfile.pi-webveil`](examples/Dockerfile.pi-webveil) builds pi + the `pi-webveil` extension + a local SearXNG (over a Unix socket, `http-socket` so webveil's `unix:` baseUrl can speak HTTP to it, JSON API on, limiter off), started by an entrypoint that then execs anon-pi's command. Note the anonymity subtlety it documents: SearXNG's own crawl is anonymized here **because netcage forces every process's egress through the proxy**, so webveil's plain `egress: direct` is correct in-jail (the usual "local SearXNG leaks your IP" caveat does not apply).
119
+ A worked example ships in this package: [`examples/Dockerfile.pi-webveil`](examples/Dockerfile.pi-webveil) builds pi + the `pi-webveil` extension (staged) + a local SearXNG (over a Unix socket, `http-socket` so webveil's `unix:` baseUrl can speak HTTP to it, JSON API on, limiter off), started by an entrypoint that then execs anon-pi's seed-then-pi command. Note the anonymity subtlety it documents: SearXNG's own crawl is anonymized here **because netcage forces every process's egress through the proxy**, so webveil's plain `egress: direct` is correct in-jail (the usual "local SearXNG leaks your IP" caveat does not apply).
101
120
 
102
121
  ## Generating the seed (`anon-pi import`)
103
122
 
104
- anon-pi **never** copies your real pi config. Instead, `anon-pi import` synthesizes a minimal seed from your local model:
123
+ anon-pi **never** copies your real pi config. Instead, `anon-pi import` synthesizes a minimal `models.json` from your local model:
105
124
 
106
125
  ```sh
107
126
  export ANON_PI_LLM=192.168.1.150:8080
108
127
  anon-pi import
109
128
  ```
110
129
 
111
- It reads your host `~/.pi/agent/models.json` (override with `ANON_PI_SOURCE_MODELS`), finds the provider whose `baseUrl` serves `ANON_PI_LLM` (matched on host:port, so `192.168.1.150:8080` matches `http://192.168.1.150:8080/v1`), and writes **just that provider** to `<ANON_PI_CONFIG>/models.json`. Everything else, your paid providers and their API keys, your sessions, your trust list, your extensions, is left behind on the host.
130
+ It reads your host `~/.pi/agent/models.json` (override with `ANON_PI_SOURCE_MODELS`), finds the provider whose `baseUrl` serves `ANON_PI_LLM` (matched on host:port, so `192.168.1.150:8080` matches `http://192.168.1.150:8080/v1`), and writes **just that provider** to `<ANON_PI_CONFIG>/models.json`. Everything else, your paid providers and their API keys, your sessions, your trust list, is left behind on the host.
131
+
132
+ That file **seeds a fresh session home** (it is copied in on first launch). Models you later add *inside* pi persist in the session home and are never clobbered by import. To change what a fresh home seeds, re-run `anon-pi import --force`; to apply it to an existing session, reset that session (delete its state home).
112
133
 
113
134
  - If no provider matches `ANON_PI_LLM`, it errors and lists the providers it did find.
114
135
  - If the matched provider carries a real-looking `apiKey` (not `none`/`ollama`/empty), it warns but proceeds (for a local model this is usually fine).
115
- - It refuses to overwrite an existing seed unless you pass `--force`.
116
-
117
- To reseed (e.g. after changing your local model), re-run `anon-pi import --force`.
136
+ - It refuses to overwrite the canonical seed unless you pass `--force`.
118
137
 
119
138
  ## Trusting `/work`
120
139
 
121
- pi treats a mounted project as untrusted until approved. For a smooth start, have the **image** trust `/work` (bake a `trust.json` mapping `/work` to `true` into the image's `~/.pi/agent`), or approve once inside a session. anon-pi does not synthesize pi's `trust.json`; it belongs in the image, alongside the extensions.
140
+ pi treats a mounted project as untrusted until approved. The shipped Dockerfiles stage a `trust.json` trusting `/work` (in `/opt/anon-pi-seed/agent`), which is promoted into the session home on first launch, so you are not prompted. You can also approve once inside a session; it persists.
122
141
 
123
142
  ## Overriding the config per workdir
124
143
 
package/dist/anon-pi.d.ts CHANGED
@@ -1,28 +1,48 @@
1
1
  /** The container path the workdir is mounted at (pi's cwd). */
2
2
  export declare const CONTAINER_WORKDIR = "/work";
3
3
  /**
4
- * Where the seed (just models.json) is mounted read-only in the container. The
5
- * run command copies models.json FROM here INTO the container's own
6
- * ~/.pi/agent, so it LAYERS onto the image's config (extensions/skills the image
7
- * installed survive) instead of replacing it. This is why we mount+copy rather
8
- * than mount-as-agent-dir: mounting over ~/.pi/agent would shadow the image's
9
- * extensions.
4
+ * The container path pi uses as its config+state home. anon-pi mounts a
5
+ * PERSISTENT host dir here (Model B), so everything pi writes, sessions,
6
+ * history, settings (your model choice), `pi install`ed extensions, downloaded
7
+ * bin/fd, survives across launches. Statefulness is the default; --ephemeral
8
+ * mounts a throwaway dir here instead.
10
9
  */
11
- export declare const CONTAINER_SEED_DIR = "/anon-pi-seed";
10
+ export declare const CONTAINER_AGENT_DIR = "/root/.pi/agent";
12
11
  /**
13
- * The container command: copy the seeded models.json into pi's own config dir
14
- * (creating it if absent), then exec pi. `$HOME/.pi/agent` is pi's default
15
- * config dir when PI_CODING_AGENT_DIR is unset, i.e. exactly where the image
16
- * installed pi + any extensions, so the copy augments rather than shadows.
12
+ * Where the image STAGES its first-launch defaults (extensions + trust.json).
13
+ * NOT the agent dir, so it never conflicts with the persistent mount. The
14
+ * entrypoint promotes these into the mounted agent dir only when the home is
15
+ * FRESH (Model C seed-if-fresh).
17
16
  */
18
- export declare const CONTAINER_RUN_CMD: string;
19
- /** The single file the seed carries: pi's model/provider registry. */
17
+ export declare const CONTAINER_STAGE_DIR = "/opt/anon-pi-seed/agent";
18
+ /**
19
+ * Where anon-pi mounts the canonical models.json (from `import`) read-only, so
20
+ * the first-launch seed can copy it into the fresh home alongside the image's
21
+ * staged defaults. Read-only: the container never writes back to the host seed.
22
+ */
23
+ export declare const CONTAINER_MODELS_SEED = "/anon-pi-seed/models.json";
24
+ /** Marker file written into the agent dir after seeding; holds the seed version. */
25
+ export declare const SEED_MARKER = ".anon-pi-seed";
26
+ /** The single file the host-side seed carries: pi's model/provider registry. */
20
27
  export declare const MODELS_FILE = "models.json";
28
+ /**
29
+ * containerRunCmd builds the container command: on a FRESH home (no seed
30
+ * marker), promote the image's staged defaults + the mounted models.json into
31
+ * the persistent agent dir and stamp the marker; then exec pi. On a seeded home
32
+ * it does nothing but exec pi, so pi's persisted state (incl. anything you
33
+ * `pi install`ed or models pi added) is used as-is and NEVER clobbered.
34
+ *
35
+ * seedVersion is written into the marker so a future image can re-seed changed
36
+ * defaults on a version bump; v1 only seeds when the marker is absent.
37
+ */
38
+ export declare function containerRunCmd(seedVersion: string): string;
39
+ /** The seed version anon-pi stamps when it seeds a fresh home (bump to re-seed). */
40
+ export declare const SEED_VERSION = "1";
21
41
  /** Inputs resolved from the environment + argv, injected so this stays pure. */
22
42
  export interface AnonPiEnv {
23
43
  /** $HOME (or an override) used to derive default paths. */
24
44
  home: string;
25
- /** socks5h proxy URL. Default socks5h://127.0.0.1:9050. */
45
+ /** socks5h proxy URL. REQUIRED (no default: the proxy is what anonymizes). */
26
46
  proxy?: string;
27
47
  /** The anon-pi home dir. Default $XDG_CONFIG_HOME/anon-pi or ~/.config/anon-pi. */
28
48
  anonPiHome?: string;
@@ -41,17 +61,34 @@ export interface AnonPiEnv {
41
61
  * `Dockerfile.pi`.
42
62
  */
43
63
  dockerfilePath?: string;
64
+ /**
65
+ * Absolute path to the shipped examples/Dockerfile.pi-webveil (pi + pi-webveil
66
+ * + SearXNG), used to make the missing-image error mention the fuller build.
67
+ */
68
+ webveilDockerfilePath?: string;
44
69
  /** `import` source models.json override (ANON_PI_SOURCE_MODELS). */
45
70
  sourceModels?: string;
46
71
  /** The host pi agent dir override (PI_CODING_AGENT_DIR), used to find models.json. */
47
72
  piAgentDir?: string;
73
+ /** When true, use a throwaway state home (no persistence). Default false. */
74
+ ephemeral?: boolean;
75
+ /** The seed version anon-pi stamps into a fresh home. Default SEED_VERSION. */
76
+ seedVersion?: string;
48
77
  }
49
78
  /** The fully-resolved run plan cli.ts executes. */
50
79
  export interface RunPlan {
51
80
  /** Absolute workdir on the host (mounted at /work). */
52
81
  workdir: string;
53
- /** The seed dir on the host (holds models.json), mounted read-only at /anon-pi-seed. */
82
+ /**
83
+ * The PERSISTENT per-workdir state dir on the host, mounted at the container's
84
+ * ~/.pi/agent. Everything pi writes here survives. For --ephemeral this is a
85
+ * throwaway path cli.ts creates + discards.
86
+ */
87
+ stateDir: string;
88
+ /** The canonical host models.json (from `import`) mounted read-only for the seed, or '' if absent. */
54
89
  configSeed: string;
90
+ /** True when this workdir has no state yet (fresh home; the seed will run). */
91
+ fresh: boolean;
55
92
  /** The argv passed to `netcage` (after the `netcage` program name). */
56
93
  netcageArgs: string[];
57
94
  }
@@ -60,8 +97,25 @@ export declare class AnonPiError extends Error {
60
97
  }
61
98
  /** Resolve the anon-pi home dir (holds the seed). */
62
99
  export declare function resolveAnonPiHome(env: AnonPiEnv): string;
63
- /** The seed dir (holds models.json), mounted read-only into the container. */
100
+ /**
101
+ * The CANONICAL host seed dir holding models.json (written by `anon-pi import`).
102
+ * Mounted read-only so the first-launch seed can copy models.json into a fresh
103
+ * persistent home. Workdir-independent (import does not need a workdir).
104
+ */
64
105
  export declare function resolveConfigSeed(env: AnonPiEnv): string;
106
+ /**
107
+ * Encode an absolute path into a directory name using pi's OWN convention (see
108
+ * pi coding-agent session-manager: `--${cwd without leading slash, / \ : -> -}--`),
109
+ * so an anon-pi state dir is readable and matches pi's mental model (no opaque
110
+ * hash). e.g. /home/u/dev/x -> --home-u-dev-x--
111
+ */
112
+ export declare function pathSlug(absPath: string): string;
113
+ /**
114
+ * The persistent per-workdir state dir on the host (mounted at the container's
115
+ * ~/.pi/agent). Keyed by the workdir via pi's path-slug convention:
116
+ * <anonPiHome>/state/<slug>/agent
117
+ */
118
+ export declare function stateAgentDir(env: AnonPiEnv, absWorkdir: string): string;
65
119
  /**
66
120
  * Normalise a proxy-less host:port key from an ANON_PI_LLM value or a provider
67
121
  * baseUrl, so `192.168.1.150:8080` matches `http://192.168.1.150:8080/v1`.
@@ -110,15 +164,25 @@ export declare function resolveSourceModelsPath(env: AnonPiEnv): string;
110
164
  /**
111
165
  * Build the run plan from the environment + the (optional) workdir arg. PURE: it
112
166
  * resolves paths and composes the netcage argv, performing NO filesystem writes
113
- * or spawns. It THROWS AnonPiError for the hard preconditions (missing image,
114
- * missing llm, missing seed models.json) so the required inputs fail loud.
167
+ * or spawns. It THROWS AnonPiError for the required inputs (image, llm, proxy).
115
168
  *
116
- * The seed (models.json) is mounted READ-ONLY at /anon-pi-seed and copied into
117
- * the container's own ~/.pi/agent by the run command, so it LAYERS onto the
118
- * image's config (image-installed extensions/skills survive) rather than
119
- * shadowing it.
169
+ * Statefulness (Model B): a persistent per-workdir host dir is mounted at the
170
+ * container's ~/.pi/agent, so pi's sessions/history/settings/extensions persist.
171
+ * First-launch seed (Model C): when that home is FRESH, the container run
172
+ * command promotes the image's staged defaults + the imported models.json into
173
+ * it and stamps a marker; thereafter pi OWNS the home and nothing is clobbered.
174
+ *
175
+ * `modelsSeedExists` reports whether the canonical import models.json exists (so
176
+ * it is mounted for the seed); `stateExists` reports whether this workdir's
177
+ * state home already exists (so `fresh` is known).
178
+ *
179
+ * --ephemeral mounts NO writable state: pi writes to the container's own
180
+ * filesystem, which netcage runs with `--rm`, so it is destroyed when the
181
+ * container exits. Nothing writable ever touches a host path; there is no
182
+ * cleanup and no leftover-on-crash. (The read-only models.json seed is still
183
+ * mounted; it is a single file anon-pi never writes to.)
120
184
  */
121
- export declare function buildRunPlan(env: AnonPiEnv, workdirArg: string | undefined, seedModelsExists: (modelsJsonPath: string) => boolean): RunPlan;
185
+ export declare function buildRunPlan(env: AnonPiEnv, workdirArg: string | undefined, modelsSeedExists: (modelsJsonPath: string) => boolean, stateExists: (stateDir: string) => boolean): RunPlan;
122
186
  /**
123
187
  * Absolute path to the Dockerfile.pi that ships with anon-pi, resolved from this
124
188
  * module's location (package root, one level up from dist/anon-pi.js), or
@@ -126,8 +190,13 @@ export declare function buildRunPlan(env: AnonPiEnv, workdirArg: string | undefi
126
190
  * build command concrete.
127
191
  */
128
192
  export declare function shippedDockerfilePath(): string | undefined;
193
+ /**
194
+ * Absolute path to the fuller pi-webveil + SearXNG example that ships with
195
+ * anon-pi (examples/Dockerfile.pi-webveil), or undefined if not found.
196
+ */
197
+ export declare function shippedWebveilDockerfilePath(): string | undefined;
129
198
  /** Read the AnonPiEnv from a process env map (kept separate so tests inject one). */
130
199
  export declare function envFromProcess(penv: Record<string, string | undefined>): AnonPiEnv;
131
200
  /** The --help text (kept here so it is covered by the same module). */
132
- export declare const HELP = "anon-pi - launch pi inside a netcage (anonymized egress + one direct local model)\n\nUSAGE\n anon-pi [WORKDIR] launch pi jailed, working in WORKDIR (default: cwd)\n anon-pi import write the seed models.json from your local model\n\n WORKDIR the host folder pi works in (mounted at /work; pi's cwd). Files pi\n writes there land on the host.\n\nWHAT IT DOES\n Runs pi inside netcage with all web/DNS egress forced through the socks5h\n proxy (fail-closed) and ONE direct hole to your local model (ANON_PI_LLM).\n The seed models.json is mounted read-only and COPIED into the container's own\n ~/.pi/agent at start, so it layers onto the image's config: extensions and\n skills you baked into the image survive. Requires `netcage`.\n\nimport\n Reads your host ~/.pi/agent/models.json, picks the provider whose baseUrl\n serves ANON_PI_LLM, and writes JUST that provider to the seed\n (<ANON_PI_CONFIG>/models.json). No other provider's API keys, no sessions, no\n identity. Re-run with --force to overwrite an existing seed.\n\nENVIRONMENT\n ANON_PI_IMAGE (required for run) image with `pi` on PATH. No image yet?\n Running anon-pi without it prints a ready-to-build\n Dockerfile.pi recipe; see the README (Providing a pi image).\n ANON_PI_LLM (required) RFC1918/link-local IP[:port] of the local model\n ANON_PI_PROXY socks5h URL (default socks5h://127.0.0.1:9050)\n ANON_PI_HOME anon-pi home (default $XDG_CONFIG_HOME/anon-pi or ~/.config/anon-pi)\n ANON_PI_CONFIG seed dir holding models.json (default <ANON_PI_HOME>/agent)\n ANON_PI_SOURCE_MODELS (import) host models.json to read (default ~/.pi/agent/models.json)\n\nRESEED\n anon-pi import --force regenerates the seed models.json.\n\nPLATFORM\n Linux only (via netcage's netns/nft jail). On macOS/Windows it works only\n inside a Linux VM, where --allow-direct to a LAN model is VM-boundary-sensitive.\n";
201
+ export declare const HELP = "anon-pi - launch pi inside a netcage (anonymized egress + one direct local model)\n\nUSAGE\n anon-pi [WORKDIR] launch pi jailed, working in WORKDIR (default: cwd)\n anon-pi import seed models.json from your local model\n\n WORKDIR the host folder pi works in (mounted at /work; pi's cwd). Files pi\n writes there land on the host.\n\nWHAT IT DOES\n Runs pi inside netcage with all web/DNS egress forced through the socks5h\n proxy (fail-closed) and ONE direct hole to your local model (ANON_PI_LLM).\n\n STATEFUL by default: a persistent per-workdir home\n (<ANON_PI_HOME>/state/<workdir>/agent) is mounted at the container's\n ~/.pi/agent, so your conversations, history, settings (model choice), and any\n extensions you `pi install` persist across launches. Re-running in the same\n folder resumes it. On a FRESH home, the image's staged defaults (extensions,\n trust) and your imported models.json are seeded in once; after that pi owns the\n home and nothing is overwritten. Requires `netcage`.\n\n --ephemeral (or ANON_PI_EPHEMERAL=1): mount NO writable state; pi writes to the\n container's own --rm layer, gone on exit. Nothing writable touches the host,\n no cleanup, no leftover-on-crash.\n\n --fresh: delete this workdir's persistent state home first, so the (possibly\n rebuilt) image's defaults + your imported models.json are re-seeded. Use it\n after rebuilding your image to pick up new extensions/config.\n\nimport\n Reads your host ~/.pi/agent/models.json, picks the provider whose baseUrl\n serves ANON_PI_LLM, and writes JUST that provider to the canonical seed\n (<ANON_PI_CONFIG>/models.json). No other provider's API keys, no sessions, no\n identity. It SEEDS a fresh home; models you later add inside pi persist and are\n never clobbered. Re-run with --force to overwrite the canonical seed.\n\nENVIRONMENT\n ANON_PI_IMAGE (required for run) image with `pi` on PATH. No image yet?\n Running anon-pi without it prints a ready-to-build\n Dockerfile.pi recipe; see the README (Providing a pi image).\n ANON_PI_LLM (required) RFC1918/link-local IP[:port] of the local model\n ANON_PI_PROXY (required) socks5h URL of your proxy (Tor/wireproxy/ssh -D).\n No default: the proxy is what anonymizes, so it is never guessed.\n ANON_PI_EPHEMERAL set to 1 for a throwaway (non-persistent) session\n ANON_PI_HOME anon-pi home (default $XDG_CONFIG_HOME/anon-pi or ~/.config/anon-pi)\n ANON_PI_CONFIG canonical seed dir holding models.json (default <ANON_PI_HOME>/agent)\n ANON_PI_SOURCE_MODELS (import) host models.json to read (default ~/.pi/agent/models.json)\n\nRESET A SESSION\n anon-pi --fresh [WORKDIR] drop the session home and re-seed on this launch.\n Or delete it by hand: rm -rf <ANON_PI_HOME>/state/<workdir-slug>/agent\n\nPLATFORM\n Linux only (via netcage's netns/nft jail). On macOS/Windows it works only\n inside a Linux VM, where --allow-direct to a LAN model is VM-boundary-sensitive.\n";
133
202
  //# sourceMappingURL=anon-pi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"anon-pi.d.ts","sourceRoot":"","sources":["../src/anon-pi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anon-pi.d.ts","sourceRoot":"","sources":["../src/anon-pi.ts"],"names":[],"mappings":"AAyBA,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE,oFAAoF;AACpF,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C,gFAAgF;AAChF,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAc3D;AAED,oFAAoF;AACpF,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC,gFAAgF;AAChF,MAAM,WAAW,SAAS;IACzB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,mDAAmD;AACnD,MAAM,WAAW,OAAO;IACvB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,sGAAsG;IACtG,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,KAAK,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,oFAAoF;AACpF,qBAAa,WAAY,SAAQ,KAAK;CAAG;AAEzC,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAOxD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAGxD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC5B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,EAAE,YAAY,CAAC;IACrB,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAC;CACzB;AAKD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,YAAY,EACxB,SAAS,EAAE,MAAM,GACf,YAAY,CAkCd;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAS9D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,gBAAgB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,EACrD,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GACxC,OAAO,CAoHT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAE1D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,GAAG,SAAS,CAEjE;AAmBD,qFAAqF;AACrF,wBAAgB,cAAc,CAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,SAAS,CAeX;AASD,uEAAuE;AACvE,eAAO,MAAM,IAAI,o+FAuDhB,CAAC"}