pi-simocracy 0.2.0 → 0.4.1

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/README.md CHANGED
@@ -1,18 +1,28 @@
1
1
  # pi-simocracy
2
2
 
3
3
  Load a [Simocracy](https://simocracy.org) sim into your [`pi`](https://github.com/mariozechner/pi-coding-agent) chat — see its
4
- pixel-art sprite render in the terminal and chat with the agent **as that sim**.
4
+ sprite render in the terminal and chat with the agent **as that sim**.
5
5
 
6
6
  ```
7
7
  /sim mr meow
8
8
  ```
9
9
 
10
10
  …fetches Mr Meow from Simocracy's ATProto indexer, renders his 32×32
11
- sprite as colored ANSI half-blocks directly in the chat, and pushes
12
- his constitution + speaking style into pi's system prompt so pi
11
+ pixel-art sprite as colored ANSI half-blocks directly in the chat, and
12
+ pushes his constitution + speaking style into pi's system prompt so pi
13
13
  roleplays as Mr Meow until you `/sim unload`.
14
14
 
15
- ![Mr Meow loaded inline in pi](demo/sim-load.gif)
15
+ <p align="center">
16
+ <img src="https://raw.githubusercontent.com/GainForest/pi-simocracy/main/demo/sim-load.gif" alt="Mr Meow (a pipoya pixel-art cat) loaded inline in pi's chat" width="760">
17
+ </p>
18
+
19
+ As of v0.4.0, codex pet sims (OpenAI hatch-pet skill output) render too —
20
+ load **Einstein** with `/sim einstein` and the WebP atlas decodes, the
21
+ idle frame crops, and the half-block ANSI render fires inline:
22
+
23
+ <p align="center">
24
+ <img src="https://raw.githubusercontent.com/GainForest/pi-simocracy/main/demo/codex-pet-load.gif" alt="Einstein (a codex pet sim with a WebP petSheet) loaded inline in pi's chat" width="760">
25
+ </p>
16
26
 
17
27
  ---
18
28
 
@@ -33,13 +43,17 @@ doesn't need it — it just rewrites pi's system prompt.
33
43
 
34
44
  ## Slash commands
35
45
 
36
- | Command | What it does |
37
- |------------------|-------------------------------------------------------------|
38
- | `/sim <name>` | Load a sim by name (fuzzy search). Multiple matches → picker. |
39
- | `/sim <at-uri>` | Load a sim by AT-URI directly (no search). |
40
- | `/sim status` | Show which sim is currently loaded. |
41
- | `/sim unload` | Drop the persona and break character cleanly. |
42
- | `/sim help` | Print usage. |
46
+ | Command | What it does |
47
+ |-------------------|-------------------------------------------------------------|
48
+ | `/sim <name>` | Load a sim by name (fuzzy search). Multiple matches → picker. |
49
+ | `/sim <at-uri>` | Load a sim by AT-URI directly (no search). |
50
+ | `/sim status` | Show which sim is currently loaded. |
51
+ | `/sim unload` | Drop the persona and break character cleanly. |
52
+ | `/sim login [handle]` | Sign in to **ATProto / Bluesky** via loopback OAuth (NOT Anthropic — pi's built-in `/login` is what does that). Required before pi can update your sim. |
53
+ | `/sim logout` | Clear the local ATProto OAuth session. |
54
+ | `/sim whoami` | Show the signed-in handle / DID. |
55
+ | `/sim my [name]` | List / pick / fuzzy-load sims you own on your PDS. Single match auto-loads; ambiguous matches open a picker. Requires `/sim login`. |
56
+ | `/sim help` | Print usage. |
43
57
 
44
58
  Examples:
45
59
 
@@ -47,20 +61,48 @@ Examples:
47
61
  /sim mr meow
48
62
  /sim Marie Curie
49
63
  /sim at://did:plc:qc42fmqqlsmdq7jiypiiigww/org.simocracy.sim/3mfo6vwfaka24
64
+ /sim login alice.bsky.social
65
+ /sim my
50
66
  /sim unload
51
67
  ```
52
68
 
53
69
  ---
54
70
 
71
+ ## Editing a sim's constitution / speaking style
72
+
73
+ There is no slash-command pipeline for this. Once you've signed in via
74
+ `/sim login` and loaded a sim you own (`/sim my`, then pick), just
75
+ **describe the change you want to pi**:
76
+
77
+ ```
78
+ > add a red line about animal welfare to the constitution
79
+ > rewrite the speaking style to drop the lenny faces and be more concise
80
+ > shorten the constitution to ~300 words and emphasise renewable energy
81
+ ```
82
+
83
+ Pi rewrites the constitution and/or speaking style itself, then calls
84
+ the `simocracy_update_sim` tool to persist the result. The tool refuses
85
+ to run if you're not signed in or you don't own the loaded sim. The
86
+ new persona takes effect on the next reply — no reload needed.
87
+
88
+ Writing goes directly to your PDS via
89
+ `com.atproto.repo.createRecord` / `putRecord` against the
90
+ `org.simocracy.agents` (constitution) and `org.simocracy.style`
91
+ (speaking style) collections — the same lexicons simocracy.org reads
92
+ back.
93
+
94
+ ---
95
+
55
96
  ## LLM-callable tools
56
97
 
57
98
  The same actions are exposed to pi as tools, so the model can drive them itself:
58
99
 
59
- | Tool | Use when |
60
- |--------------------------|-----------------------------------------------------------------|
61
- | `simocracy_load_sim` | Load a sim into the current session (sets the persona). |
62
- | `simocracy_unload_sim` | Stop roleplaying. |
63
- | `simocracy_chat` | Send one message to a sim and get a quoted reply, **without** changing the active session persona. Useful for "ask Mr Meow what he thinks of this PR." Requires `OPENROUTER_API_KEY`. |
100
+ | Tool | Use when |
101
+ |-------------------------|-----------------------------------------------------------------|
102
+ | `simocracy_load_sim` | Load a sim into the current session (sets the persona). |
103
+ | `simocracy_unload_sim` | Stop roleplaying. |
104
+ | `simocracy_chat` | Send one message to a sim and get a quoted reply, **without** changing the active session persona. Useful for "ask Mr Meow what he thinks of this PR." Requires `OPENROUTER_API_KEY`. |
105
+ | `simocracy_update_sim` | Write a new constitution (`shortDescription` + `description`) and/or speaking `style` for the **loaded** sim to your PDS. Requires `/sim login` AND ownership of the loaded sim. |
64
106
 
65
107
  ---
66
108
 
@@ -77,11 +119,18 @@ The same actions are exposed to pi as tools, so the model can drive them itself:
77
119
  - `org.simocracy.sim` — display name + sprite + avatar blob refs
78
120
  - `org.simocracy.agents` — short description + full constitution
79
121
  - `org.simocracy.style` — speaking style / mannerisms
80
- 4. **Render.** Fetch the sprite-sheet blob (128×128 PNG, 4×4 of 32×32
81
- walking frames) via `com.atproto.sync.getBlob`, decode with `pngjs`,
82
- crop the front-facing walk-1 frame, emit as 24-bit ANSI using the
83
- upper-half-block character `▀` so each terminal cell paints two
84
- pixels. Transparent regions show pi's background through.
122
+ 4. **Render.** Fetch the sprite blob via `com.atproto.sync.getBlob`,
123
+ decode it, crop the front-facing idle frame, and emit as 24-bit ANSI
124
+ using the upper-half-block character `▀` so each terminal cell paints
125
+ two pixels. Two render paths depending on the sim's `spriteKind`:
126
+ - **`pipoya`** (legacy + default): 128×128 PNG, 4×4 of 32×32 walking
127
+ frames; decode with `pngjs`, take row 0 col 0 at native size.
128
+ - **`codexPet`** (OpenAI hatch-pet output): 1536×1872 atlas, 8×9 of
129
+ 192×208 cells. PNG sheets decode through `pngjs`; WebP sheets
130
+ decode through `@jsquash/webp` (wasm, lazy-init). The idle cell
131
+ (row 0 col 0) is box-downscaled to ~32 wide so the inline render
132
+ stays comparable in height to a pipoya sprite.
133
+ Transparent regions show pi's background through.
85
134
  5. **Inject.** A `before_agent_start` event handler appends the sim's
86
135
  identity + constitution + speaking style to pi's system prompt **every
87
136
  turn**. After `/sim unload`, a one-shot override fires on the next
@@ -97,12 +146,17 @@ keeps the terminal it's already running in.
97
146
 
98
147
  ```
99
148
  src/
100
- ├── index.ts # extension entry: slash command, tools, persona injection
101
- ├── simocracy.ts # indexer + PDS client (read-only)
102
- ├── png-to-ansi.ts # RGBA half-block ANSI renderer
103
- └── openrouter.ts # minimal OpenRouter client (only used by simocracy_chat)
149
+ ├── index.ts # extension entry: slash command, tools, persona injection
150
+ ├── persona.ts # buildSimPrompt(sim) the system-prompt fragment
151
+ ├── simocracy.ts # indexer + PDS client (read-only fetchers)
152
+ ├── writes.ts # PDS writers + ownership / sign-in preconditions
153
+ ├── png-to-ansi.ts # RGBA half-block ANSI renderer + downscalers
154
+ ├── webp-to-rgba.ts # @jsquash/webp wrapper for codex pet WebP sheets
155
+ ├── openrouter.ts # minimal OpenRouter client (only used by simocracy_chat)
156
+ └── auth/ # ATProto OAuth loopback flow + session storage
104
157
  demo/
105
- └── sim-load.tape # vhs tape — render with `vhs demo/sim-load.tape`
158
+ ├── sim-load.tape # vhs tape — Mr Meow (pipoya)
159
+ └── codex-pet-load.tape # vhs tape — Einstein (codex pet)
106
160
  ```
107
161
 
108
162
  ---
@@ -118,11 +172,12 @@ pi -e $(pwd)/src/index.ts -ne -ns # load the extension directly
118
172
 
119
173
  Then in `pi`: `/sim mr meow`.
120
174
 
121
- To rebuild the demo recording:
175
+ To rebuild the demo recordings:
122
176
 
123
177
  ```bash
124
178
  brew install vhs # one-time
125
- vhs demo/sim-load.tape # writes demo/sim-load.{webm,gif}
179
+ vhs demo/sim-load.tape # Mr Meow (pipoya) — demo/sim-load.{webm,gif}
180
+ vhs demo/codex-pet-load.tape # Einstein (codex pet) — demo/codex-pet-load.{webm,gif}
126
181
  ```
127
182
 
128
183
  ---
@@ -137,7 +192,11 @@ These come bundled with `pi` itself, so installing pi-simocracy via
137
192
 
138
193
  Direct npm dependencies (auto-installed):
139
194
 
140
- - `pngjs` — PNG decoder for sprite blobs
195
+ - `pngjs` — PNG decoder for pipoya sprite blobs and codex pet PNG sheets
196
+ - `@jsquash/webp` — wasm WebP decoder for codex pet WebP sheets
197
+ (lazy-init, no native bindings)
198
+ - `@atproto/api` + `@atproto/oauth-client-node` — ATProto loopback OAuth
199
+ for `/sim login` and PDS writes via `simocracy_update_sim`
141
200
  - `typebox` — tool parameter schemas
142
201
 
143
202
  ---
@@ -157,4 +216,4 @@ Direct npm dependencies (auto-installed):
157
216
 
158
217
  ## License
159
218
 
160
- MIT — see [LICENSE](./LICENSE).
219
+ MIT — see [LICENSE](https://github.com/GainForest/pi-simocracy/blob/main/LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-simocracy",
3
- "version": "0.2.0",
3
+ "version": "0.4.1",
4
4
  "description": "Pi extension: load a Simocracy sim into your chat — see its pixel-art sprite render inline in the terminal and roleplay with it.",
5
5
  "type": "module",
6
6
  "author": "David Dao <david@gainforest.earth> (https://github.com/daviddao)",
@@ -45,6 +45,7 @@
45
45
  "dependencies": {
46
46
  "@atproto/api": "^0.19.11",
47
47
  "@atproto/oauth-client-node": "^0.3.17",
48
+ "@jsquash/webp": "^1.5.0",
48
49
  "pngjs": "^7.0.0",
49
50
  "typebox": "^1.1.24"
50
51
  },
@@ -106,8 +106,8 @@ export async function runLogin(
106
106
 
107
107
  ctx.ui.notify(
108
108
  handleResolved
109
- ? `🔐 Signed in to ATProto as @${handleResolved} (${did}). You can now use /sim interview --apply and /sim train apply --apply to write to your PDS.`
110
- : `🔐 Signed in to ATProto as ${did}. You can now use /sim interview --apply and /sim train apply --apply to write to your PDS.`,
109
+ ? `🔐 Signed in to ATProto as @${handleResolved} (${did}). Pi can now update the constitution / speaking style of any sim you own via the simocracy_update_sim tool — just load one of your sims with /sim my and ask pi for the change you want.`
110
+ : `🔐 Signed in to ATProto as ${did}. Pi can now update the constitution / speaking style of any sim you own via the simocracy_update_sim tool — just load one of your sims with /sim my and ask pi for the change you want.`,
111
111
  "info",
112
112
  );
113
113
  } finally {
@@ -139,8 +139,8 @@ export async function runWhoami(ctx: ExtensionCommandContext): Promise<void> {
139
139
  }
140
140
  ctx.ui.notify(
141
141
  auth.handle
142
- ? `Signed into ATProto as @${auth.handle} (${auth.did}) since ${auth.lastLogin}. Use /sim interview --apply or /sim train apply --apply to write records to your PDS.`
143
- : `Signed into ATProto as ${auth.did} since ${auth.lastLogin}. Use /sim interview --apply or /sim train apply --apply to write records to your PDS.`,
142
+ ? `Signed into ATProto as @${auth.handle} (${auth.did}) since ${auth.lastLogin}. Pi can update the constitution / speaking style of any sim you own (loaded via /sim my) by calling the simocracy_update_sim tool.`
143
+ : `Signed into ATProto as ${auth.did} since ${auth.lastLogin}. Pi can update the constitution / speaking style of any sim you own (loaded via /sim my) by calling the simocracy_update_sim tool.`,
144
144
  "info",
145
145
  );
146
146
  }