fisi-dock 0.0.0-stage → 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ ## 0.2.1
4
+
5
+ ### Project
6
+
7
+ - Published on npm: `gentle-shell install npm:fisi-dock`.
8
+ - `docs/screenshot.png`, a cover with the GENTLESHELL wordmark, the name and the ODD, agents and todo sections, set as the package's `pi.image` preview for the Pi package gallery. It stays in the repository and out of the npm package.
9
+ - The security policy says fixes reach `main` and the latest release.
10
+
11
+ ## 0.2.0
12
+
13
+ ### Start screen
14
+
15
+ - A welcome card replaces Gentle Shell's rose banner: `Gentle Shell <version>` with `with Fisi Dock`, `Ready in <project> on <branch>.`, the five commands to begin with (`/resume`, `/new`, `/changelog`, `/hotkeys`, `/quit`) and the alt+k tip. It shows only when Gentle Shell's `gentle:banner` command exists; without Gentle Shell, Pi keeps its own startup header and listing.
16
+ - Under the card, Pi's list of loaded skills, prompts and extensions is one `loaded` box in the card's frame: one row per kind with its count and as many names as fit, and `<key> lists them` on the bottom rule. The key is your real expand key: the one Pi's editor holds, else the `app.tools.expand` (or legacy `expandTools`) binding in Pi's `keybindings.json`, else Pi's default `ctrl+o`; a key unbound with `[]` drops the hint. Pressing it shows Pi's full listing.
17
+ - Pi's warnings (`[Skill warnings]`, `[Prompt conflicts]`, `[Extension issues]`, `[Theme conflicts]`) always print under the box. A Pi listing of a shape Fisi Dock does not recognize is left as it is.
18
+ - `/fisi-dock off` and session shutdown give Pi's own header and listing back.
19
+
20
+ ### Session section
21
+
22
+ - Grouped (design session-section/02): `where ──`, `usage ──` and `connections ──` labels instead of a flat list, with one key column. On short screens the three labels are the first rows to go.
23
+ - The context meter and its `5% · 53.5k/1M` readout share a row (the readout moves under the bar on a 34-column rail); filled cells in the state color, empty ones a thin faint `─`. The cost sits flush right on the `profile` row.
24
+ - New `memory` row for Engram (gentle-engram's `mem_*` tools, not MCP): `○ not installed`, `● connected · N saved` from this session's successful `mem_save` calls, or `✗ unreachable` after a failed `mem_*` call until the next one succeeds. Nothing is spawned.
25
+ - MCP servers get one row each (`● connected`, `◌ connecting`, `✗ failed`); no MCP config says `mcp none configured`.
26
+ - Many MCP servers: the rail shows at most 4 `mcp` rows. With 5 or more, 3 servers keep a row (failed first, then connecting, then connected, config order within each) and the fourth sums up the rest: `+7 more · 2 connecting · 5 connected`, the counts dropping from the right on a narrow rail. `/dock` still lists every server.
27
+
28
+ ### Prompt box on narrow screens
29
+
30
+ - The labels compact instead of vanishing: tight separators (`● SUPER-YOLO opus-5.5·high`), then no effort (`● SUPER-YOLO opus-5.5`), then the mode alone (the model alone in normal mode), each tried beside Gentle Shell's hint first. Working at 40 columns reads `╭─ ✿ working… ─ ● SUPER-YOLO opus-5.5 ─╮`. The line under the prompt compacts the same way before it is cut.
31
+ - On a phone, idle, the mode, model and effort stay: too tight for them beside `waiting for input`, the rule drops the label's words and keeps the petal (`╭─ ✿ ──── ● SUPER-YOLO opus-5.5 · high ─╮`).
32
+ - The idle label is told by how Gentle Shell paints it (whole; not the working scan, `queued`, an ODD phase or the `↑ 3 more` scroll indicator), not by the words `waiting for input`, so a translated, custom or clipped idle label (`waiting for i…`) gets the same rule.
33
+
34
+ ### Wordmark
35
+
36
+ - The rail logo reads GENTLESHELL, joined, GENTLE gray and SHELL in Gentle Shell's Gentleman-Sexy pink (#F43888), drawn in braille dots (gray fade, Sexy pink to its deep pink #BF0F50). The 55-column rail gets the wide 51-column mark; the official 47-column rail gets the 45-column compact one (the same G, N and L, a narrower E, T, S and H), centered with one blank column on each side. Narrower rails show one bold text row, letters spaced (`G E N T L E S H E L L`) down to 21 columns and joined below.
37
+
38
+ ### Fixes
39
+
40
+ - The first start applies the `Fisi-Dock` theme once and remembers yours first, so `/fisi-dock off` gives back exactly the theme you had instead of `Gentleman-Cute`: `Fisi Dock applied its theme · /fisi-dock off puts your theme dark back`. Installs from before get it once on their next start; later starts keep any theme picked in `/settings`. The state file records it as `"themeApplied": true`. Skipped while off, in delegated child sessions, when Pi lacks the theme or cannot set it (tried again next start), and when the state file cannot be written.
41
+ - On Gentle Shell builds that card rail parts (its `main` branch, transparent surface) the panel no longer loses its right border to a `…`.
42
+
43
+ ### Tests and CI
44
+
45
+ - `tests/configs.test.ts`: simulated user configurations (another language, no Engram, ten MCP servers, Vim on, a 30-column screen, a remapped or unbound expand key, all at once, and no Gentle Shell) drive the extension end to end, and every surface is checked at every width from 0 to 140.
46
+ - The Gentle Shell key check finds the package Gentle Shell itself loads (the one its launcher injects, else the `gentle-shell` launcher's own on PATH, pnpm included) before the global npm root, preferring the version provisioned in `~/.gentle-shell/config.json`. It no longer skips on a pnpm install, and still skips with no Gentle Shell (CI).
47
+ - CI runs `npm ci` before the tests, so they get Pi's real TUI classes and source.
48
+
49
+ ### Project
50
+
51
+ - Contributing guide, security policy, issue forms for bugs and ideas, and a pull request template.
52
+
53
+ ## 0.1.0
54
+
55
+ First release.
56
+
57
+ - Side panel in Gentle Shell's fullscreen rail: `session` (project, branch, context, model profile, cost, MCP servers), `heads-up`, `ODD`, `RDD`, `CI`, `agents`, `todo` and `changes`, with short-screen shapes.
58
+ - Prompt box with the working label, permission mode, model and effort on its border.
59
+ - Narrow screens: top row, strip, agents and todo cards; `/dock` for the whole panel.
60
+ - `/fisi-dock on` | `off`, remembered across restarts; off puts your previous theme back.
61
+ - `Fisi-Dock` theme.
62
+ - Tested with Gentle Shell 4.6.0.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fisi Dj
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,224 @@
1
- # Temporary Holding Version
1
+ # Fisi Dock
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **A side panel for [Gentle Shell](https://github.com/Gentleman-Programming/gentle-shell): your session, ODD phases, RDD reviews, CI, agents, todo list and changes at a glance.**
4
+
5
+ Fisi Dock is an alternative look for Gentle Shell, for people who want a different interface from Gentle Shell's default one: a side panel layout with its own colors and its own `Fisi-Dock` theme. It is built on top of Gentle Shell and does not replace it: Gentle Shell stays installed and keeps running underneath, and Fisi Dock only repaints the parts you see.
6
+
7
+ It is a Pi package (an extension and a theme) that paints its own panel in Gentle Shell's fullscreen right rail, closes the prompt into a framed box, puts a welcome card on the start screen and adds a compact strip and cards on narrow screens such as a phone over SSH. It never changes a Gentle Shell file, and `/fisi-dock off` gives Gentle Shell everything back.
8
+
9
+ > Fisi Dock is a community project. It is not an official Gentle Shell or Gentleman Programming project, and it is not endorsed by them.
10
+
11
+ ```text
12
+ ╭─ session ───────────────────────────────────╮
13
+ │ where ── │
14
+ │ project my-sample-app main ↑1 │
15
+ │ usage ── │
16
+ │ context ━─────────┼────┼── 6% · 12.1k/200k │
17
+ │ profile claude $0.012 │
18
+ │ connections ── │
19
+ │ memory ● engram connected · 3 saved │
20
+ │ mcp ● context7 connected │
21
+ │ ● github connected │
22
+ ╰─────────────────────────────────────────────╯
23
+ ╭─ ODD ───────────────────────────────────────╮
24
+ │ ✓ exploring 0:31 │
25
+ │ ✓ implementing 1:12 │
26
+ │▎⡿ checking 0:42 │
27
+ ╰─────────────────────────────────────────────╯
28
+ ╭─ agents ────────────────────────────────────╮
29
+ │ ✓ explore Map CI workflow │
30
+ │ ⠹ writer pin the Node version opus · high │
31
+ ╰─────────────────────────────────────────────╯
32
+ ╭─ todo ──────────────────────────────── 3/7 ─╮
33
+ │ ✓ 3 done ▰▰▰▱▱▱▱ │
34
+ │▎⠹ Confirm CI is green │
35
+ │ ○ Commit workflow fix │
36
+ ╰─────────────────────────────────────────────╯
37
+ ```
38
+
39
+ (Sample data, from `node scripts/preview.ts 47`; in the terminal every section has its own color.)
40
+
41
+ ## What you get
42
+
43
+ - **Side panel** in the fullscreen rail, one framed section each: `session` in three groups (`where`: project and branch; `usage`: context meter, model profile and cost; `connections`: Engram memory and MCP servers), `heads-up` (worktrees, unpushed commits, open plans), `ODD`, `RDD`, `CI` (GitHub Actions of the branch), `agents`, `todo` and `changes`. On short screens the least urgent rows and sections step aside first.
44
+ - **Start screen**: a welcome card in place of Gentle Shell's rose banner (Gentle Shell's version, the project and branch, the commands to begin with), and Pi's list of loaded skills, prompts and extensions folded into one `loaded` box under it. Your expand key (`ctrl+o` by default) shows Pi's full listing; Pi's warnings always show.
45
+ - **Prompt box**: Gentle Shell's prompt framed, with the working label (`ODD exploring…`), the permission mode, the model and the effort on its top border.
46
+ - **Narrow screens and phones**: a one-line top row, a strip above the prompt, and compact agents and todo cards.
47
+ - **`/dock`** and **`/fisi-dock`**: the whole panel over the screen, and an on/off switch that needs no uninstall ([Commands](#commands)).
48
+ - **`Fisi-Dock` theme**: the panel's palette for the whole of Pi, applied once on the first start with your own theme remembered for `/fisi-dock off` ([Theme](#theme)).
49
+
50
+ Every section, row and data source is described in [docs/reference.md](docs/reference.md).
51
+
52
+ ## Adapts to your setup
53
+
54
+ | Your setup | What Fisi Dock does |
55
+ |---|---|
56
+ | Narrow screen or phone | The strip, cards and top row stand in for the rail. On the prompt box the labels compact step by step instead of vanishing: tight separators, then no effort, then the mode alone (the model alone in normal mode). Idle, the label's words give way first so the labels stay. Under 34 columns the welcome card keeps only its title and ready lines. |
57
+ | Gentle Shell in another language | The idle prompt label is told by how Gentle Shell paints it, not by its words, so a translated or custom label behaves the same. |
58
+ | No Engram | The `memory` row says `not installed`. With Engram, a failed `mem_*` call shows `unreachable` until the next one succeeds. Fisi Dock starts no process and asks no server. |
59
+ | No MCP servers | The `mcp` row says `none configured`. |
60
+ | Many MCP servers | The rail shows at most 4 `mcp` rows: problems first, then `+N more` with a count per state. `/dock` lists every server. |
61
+ | Remapped expand key | The `loaded` box names your key, from Pi's editor or Pi's `keybindings.json`; a key bound to nothing drops the hint. |
62
+ | Vim mode on | Gentle Shell's `INSERT`/`NORMAL` hint stays on the prompt's top rule and the labels compact to make room for it. With no room for both, the hint wins while working and the labels win while idle. |
63
+ | Reduced motion | Gentle Shell's `potato` animation level, or `FISI_DOCK_ORBS=off`, stills the orb and spinners. |
64
+ | No Gentle Shell | Fisi Dock stays out of the way: no rail, strip, cards, prompt box or welcome card, and Pi keeps its own startup header and listing. `/dock` still opens the panel. |
65
+
66
+ ## Requirements
67
+
68
+ - **Gentle Shell** (the `gentle-pi` npm package). Fisi Dock is tested with **Gentle Shell 4.6.0**. It reads Gentle Shell's shared state by name and imports nothing from it, so on another version a part it no longer recognizes stops painting instead of breaking the session.
69
+ - **Node.js 22.19 or later** (the one Gentle Shell runs on).
70
+ - **Fullscreen mode** for the side panel, with a terminal at least 140 columns wide; narrower terminals get the strip, the cards and `/dock`.
71
+ - Optional: **`git`** for branch, changes and heads-up; **GitHub CLI (`gh`)**, signed in, for the `CI` section; **Gentle AI** for the `RDD` switch; **gentle-engram** (Gentle Shell's Engram package) for a connected `memory` row; MCP servers in Pi's `mcp.json` for the `mcp` rows. A missing tool only leaves its section out or says so in its row.
72
+
73
+ Works on Windows, macOS and Linux.
74
+
75
+ ## Install
76
+
77
+ Install it into Gentle Shell from GitHub, so it loads every time Gentle Shell starts:
78
+
79
+ ```bash
80
+ gentle-shell install git:github.com/fisidj/fisi-dock
81
+ ```
82
+
83
+ Without a tag you follow the `main` branch. Releases are tagged `vX.Y.Z` and listed on the [Releases page](https://github.com/fisidj/fisi-dock/releases); the latest is `v0.2.1`. To pin one, add `@<tag>` to the source: `gentle-shell install git:github.com/fisidj/fisi-dock@v0.2.1`. Pi keeps a pinned tag: updates do not move it.
84
+
85
+ Fisi Dock is also on npm: `gentle-shell install npm:fisi-dock`, pinned with `npm:fisi-dock@0.2.1`.
86
+
87
+ If you run Gentle Shell with `--link` (Pi's own home instead of the launcher's isolated one), install it there instead: `gentle-shell --link install git:github.com/fisidj/fisi-dock`.
88
+
89
+ Try it for one session without installing:
90
+
91
+ ```bash
92
+ gentle-shell -e git:github.com/fisidj/fisi-dock
93
+ ```
94
+
95
+ Then start Gentle Shell as usual. The panel, prompt box and welcome card are on from the first session, and that first session switches Pi to the `Fisi-Dock` theme once, remembering yours: see [Theme](#theme) to keep your own.
96
+
97
+ As with any Pi package, Fisi Dock runs code on your machine: review the source before installing it.
98
+
99
+ ## Commands
100
+
101
+ Fisi Dock adds two commands:
102
+
103
+ | Command | What it does |
104
+ |---|---|
105
+ | `/dock` | Shows the full panel over the whole screen, live. Made for narrow screens without the side rail; works on wide ones too. While Fisi Dock is off it only says so. |
106
+ | `/fisi-dock on` | Turns Fisi Dock back on, as at the start of a session, and switches Pi to the `Fisi-Dock` theme, remembering the theme you had. Already on: it says so and changes nothing. |
107
+ | `/fisi-dock off` | Puts Fisi Dock to sleep without uninstalling it: Gentle Shell gets its own panel back, and your theme comes back (see [Theme](#theme)). New sessions start asleep until `/fisi-dock on`. |
108
+ | `/fisi-dock` | Opens a picker titled with the current state (`Fisi Dock is on`), the change listed first: Enter switches it, Esc changes nothing. Typing `/fisi-dock ` with the space suggests `on` and `off`; any other argument shows the usage and changes nothing. |
109
+
110
+ Inside `/dock`:
111
+
112
+ | Key | Action |
113
+ |---|---|
114
+ | ↑ / ↓ | Scroll one row |
115
+ | Page Up / Page Down | Scroll one page |
116
+ | Mouse wheel, or a finger swipe on a phone terminal that sends swipes as the wheel | Scroll |
117
+ | Esc | Close and return to the prompt |
118
+
119
+ Gentle Shell and Pi controls that change what Fisi Dock shows:
120
+
121
+ | Control | Effect on Fisi Dock |
122
+ |---|---|
123
+ | `/settings` → **Theme** | Picks any theme, `Fisi-Dock` included ([Theme](#theme)). |
124
+ | Your expand key (`ctrl+o` by default) | Shows Pi's full list of loaded skills, prompts and extensions in place of the `loaded` box; press it again for the box. |
125
+ | `/gentle:vim disable` | Turns Gentle Shell's Vim mode off, and with it the `INSERT`/`NORMAL` hint on the prompt box. `/gentle:vim enable` turns it back on. |
126
+ | `"quietStartup": true` in Pi's `settings.json` | Pi prints no loaded-resources listing, so there is no `loaded` box. |
127
+
128
+ ## Theme
129
+
130
+ `Fisi-Dock` is a Pi theme with the panel's palette and a pink-tinted selection. It colors the whole of Pi, not only the panel. It is optional: the panel keeps its own colors with any theme.
131
+
132
+ **The first start applies it once.** The first session with Fisi Dock on, inside Gentle Shell, remembers the theme you use, then switches Pi to `Fisi-Dock` and says so: `Fisi Dock applied its theme · /fisi-dock off puts your theme dark back`. This happens once, also on an install from before this step; every later start leaves your theme alone. It waits for the next start when Pi does not know the `Fisi-Dock` theme or cannot set it, and it never changes your theme when Fisi Dock cannot save the one you had. It never runs in a delegated subagent session, and a Fisi Dock that is off does nothing at start: `/fisi-dock on` sets the theme instead.
133
+
134
+ | How | What happens |
135
+ |---|---|
136
+ | The first start | Once, as above. Your theme is remembered for `/fisi-dock off`. |
137
+ | `/fisi-dock off`, then `/fisi-dock on` | On remembers the theme in use and sets `Fisi-Dock` (`/fisi-dock on` while already on changes nothing). |
138
+ | `/settings` → **Theme** → `Fisi-Dock` | Pi switches now and saves it as your theme setting. Nothing new is remembered, so a later `/fisi-dock off` gives back the theme remembered before, else Gentle Shell's `Gentleman-Cute`. |
139
+
140
+ To keep your own theme after the first start, or to switch back:
141
+
142
+ - `/settings` → **Theme**, and pick any theme, Gentle Shell's `Gentleman-Cute` included: the panel stays on and later starts keep that theme; or
143
+ - `/fisi-dock off`: it puts back the remembered theme (the one you had at the first start or at your last `/fisi-dock on`), else `Gentleman-Cute`, and puts the panel to sleep too. A remembered theme Pi no longer knows is skipped, and off says so.
144
+
145
+ Both `/fisi-dock` and `/settings` go through Pi's own theme setting, so the change lasts across restarts.
146
+
147
+ ## Turn it off, disable or remove
148
+
149
+ Three levels, from lightest to complete:
150
+
151
+ | Goal | How | Back on |
152
+ |---|---|---|
153
+ | Turn it off for now, keep it installed | `/fisi-dock off` inside Gentle Shell. Remembered across restarts. | `/fisi-dock on` |
154
+ | Disable the package, keep it installed | `gentle-shell config`: Pi's picker of the resources every installed package loads; turn off Fisi Dock's extension (and its theme, if you like). Applies on the next start. | `gentle-shell config` again |
155
+ | Uninstall | `gentle-shell remove git:github.com/fisidj/fisi-dock` (`uninstall` is the same command) | `gentle-shell install git:github.com/fisidj/fisi-dock` |
156
+
157
+ If you installed with `--link`, put it before the subcommand: `gentle-shell --link config`, `gentle-shell --link remove git:github.com/fisidj/fisi-dock`.
158
+
159
+ **What you get back**, in all three cases: Gentle Shell's own panel (its rail sections, top row and status bar), its prompt editor in place of the box, Pi's own startup header and loaded-resources listing, and Gentle Shell's rose banner (on the next start or `/reload` after `/fisi-dock off`).
160
+
161
+ **Your theme** comes back only with `/fisi-dock off`. `gentle-shell config` and `remove` leave Pi's theme setting as it is. If that setting is `Fisi-Dock` when the theme is no longer loaded, Pi falls back to its `system` theme without a warning. So run `/fisi-dock off` first, or pick a theme in `/settings` afterwards.
162
+
163
+ **What stays**: the state file `fisi-dock/state.json` in Pi's agent dir (`PI_CODING_AGENT_DIR`, which Gentle Shell sets to its home: `~/.gentle-shell/agent/fisi-dock/state.json` by default, `~/.pi/agent/fisi-dock/state.json` with `--link`). It holds only the on/off choice, the remembered theme and whether the first start already applied the theme, for example `{ "enabled": false, "theme": "dark", "themeApplied": true }`. Removing Fisi Dock does not delete it, and it is safe to delete: without it Fisi Dock starts on, remembers no theme and applies its theme again on the next start.
164
+
165
+ ## Update
166
+
167
+ ```bash
168
+ gentle-shell update git:github.com/fisidj/fisi-dock
169
+ ```
170
+
171
+ `gentle-shell update <source>` runs Pi's update for that one package: without a tag it moves to the latest `main`; pinned to a tag it stays on that tag. To move to another release, run `gentle-shell install` again with the new tag; Pi replaces the entry. `gentle-shell update --extensions` updates every installed package at once (`gentle-shell update` alone updates Pi itself).
172
+
173
+ ## How it works
174
+
175
+ Fisi Dock takes over, and paints its own:
176
+
177
+ - Gentle Shell's rail parts and top row, through Gentle Shell's shared sidebar state;
178
+ - Gentle Shell's prompt editor frame, by wrapping its editor factory;
179
+ - Pi's startup header (the welcome card, through `ctx.ui.setHeader`) and the render of Pi's loaded-resources listing (the `loaded` box), only while Gentle Shell's `gentle:banner` command exists.
180
+
181
+ It reads the rest from Gentle Shell's events, its ODD phase and profile registries, Pi's session and tool list, and read-only `git`, `gh` and `gentle-ai` calls. The files it reads:
182
+
183
+ | File | For |
184
+ |---|---|
185
+ | Pi's `mcp.json` (global and the project's `.pi/mcp.json`) | the `mcp` rows; only server names and their on/off switch |
186
+ | Pi's `keybindings.json` | the expand key on the `loaded` box |
187
+ | Gentle Shell's `config.json` beside its agent home (`~/.gentle-shell/config.json` by default) | the version on the welcome card |
188
+ | Gentle Shell's `animations.json` | the animation level |
189
+ | Gentle Shell's subagent presence file | subagents already running after a `/reload` |
190
+ | The project's `odd/tasks/*.md` | open ODD plans in `heads-up` |
191
+
192
+ It writes only its own `state.json` and your Pi theme setting: once on the first start, and when `/fisi-dock` switches it on or off. When it unloads, or with `/fisi-dock off`, Gentle Shell and Pi get every original part back. Details: [docs/reference.md](docs/reference.md).
193
+
194
+ ## Develop
195
+
196
+ ```bash
197
+ git clone https://github.com/fisidj/fisi-dock
198
+ cd fisi-dock
199
+ npm ci
200
+ npm test
201
+ ```
202
+
203
+ Tests run on Node 22.19 or later with native TypeScript; no build step. They need the dev dependencies (Pi's real TUI classes and its source), so run `npm ci` first, as CI does. `tests/configs.test.ts` drives Fisi Dock through simulated user configurations (another language, no Engram, ten MCP servers, Vim, a 30-column screen, a remapped or unbound expand key, no Gentle Shell) and checks every surface at every width from 0 to 140, against a fresh temp folder, never your own configuration. `tests/gentle-shell-keys.test.ts` also checks the installed Gentle Shell (`GENTLE_SHELL_DIR`, else the `gentle-pi` package Gentle Shell itself runs, found from its session environment or its `gentle-shell` launcher on `PATH`, pnpm or npm, else `gentle-pi` in the global npm root; among several, the version provisioned in `~/.gentle-shell/config.json`) still defines every key Fisi Dock reads, and is skipped without it.
204
+
205
+ Preview the panel with sample data in a terminal (width defaults to 47, the rail's usable width), or write an HTML page for screenshots:
206
+
207
+ ```bash
208
+ node scripts/preview.ts 47
209
+ node scripts/preview.ts --html tmp/panel-47.html
210
+ node scripts/preview.ts 64 --strip
211
+ node scripts/preview.ts --dock
212
+ node scripts/preview.ts 64 --header
213
+ node scripts/preview.ts 58 --rows 28
214
+ ```
215
+
216
+ `--strip` prints the narrow-screen strip, `--dock` the `/dock` box, `--header` the narrow top row, and `--rows <n>` the panel as it fits a terminal `<n>` rows tall. `tmp/` is git-ignored.
217
+
218
+ ## Contributing
219
+
220
+ Issues and pull requests are welcome: [CONTRIBUTING.md](CONTRIBUTING.md) covers what makes a good bug report, the test and docs rules, and how to try a checkout in Gentle Shell. Report a vulnerability privately, as [SECURITY.md](SECURITY.md) describes. Everyone taking part follows the [Code of Conduct](CODE_OF_CONDUCT.md).
221
+
222
+ ## License
223
+
224
+ [MIT](LICENSE)
@@ -0,0 +1,115 @@
1
+ # Fisi Dock reference
2
+
3
+ Everything Fisi Dock draws, where each piece of data comes from, and how it fits into Gentle Shell. For installing and a quick start, see the [README](../README.md).
4
+
5
+ ## What it changes
6
+
7
+ While Gentle Shell's fullscreen rail is on screen (fullscreen mode, terminal at least 140 columns wide, Status placement `auto` or `right`):
8
+
9
+ - **Side panel**: replaces the rail's Status section with the Fisi Dock panel: the GENTLESHELL wordmark, then framed `session`, `heads-up` (only when something is left open), `ODD` (always on screen), `RDD`, `CI` (only while the branch has GitHub Actions runs), `agents`, `todo` (always on screen) and `changes` sections, in that order, each section in its own color. Context, cost, the model profile, Engram memory and MCP servers are rows inside `session`; reviews have their own `RDD` section; there is no footer under the panel. Gentle Shell builds that wrap rail parts in their own cards (the transparent chrome surface on its `main` branch) get every panel row as a loose row, so the panel keeps its own frames instead of sitting inside a host card that would cut its right border.
10
+ - **Only this panel in the rail**: Gentle Shell's own `todo`, `jobs` and `agents` rail sections and the status bar it paints under the rail (branch, permission mode, model, effort, context, cost) are taken over with parts that paint nothing, the same way the Status section and the top row are, so nothing repeats; Gentle Shell gets every original back when Fisi Dock unloads.
11
+ - **Short screens**: when the panel is taller than the terminal (its rows minus the top row and the gap under it), it leaves out, in this order and only as far as needed, the `session` section's three group labels (`where ──`, `usage ──`, `connections ──`), then the `│` spacer rows between ODD steps and between RDD reviews (the gray lines under finished ODD steps and finished RDD reviews drop with them; the active step and a running review keep their line; the gray lines under the `CI` rows drop with them too), then the `changes` section, then the `CI` section when every check passed, then the `CI` section while a check runs, waits or failed, then the `RDD` section together with every ODD row but the latest step while a request runs. The wordmark, `session`, `heads-up`, `ODD` (at least its title and one row), `agents` and `todo` are never left out; if the panel is still too tall, the rail scrolls. `/dock` is not affected: it scrolls and shows everything.
12
+ - **Start screen**: when Gentle Shell's `gentle:banner` command exists, the header Pi shows above the chat at startup is Fisi Dock's welcome card instead of Gentle Shell's rose banner (design 08): a gray frame with `Gentle Shell <version>` and a pink `with Fisi Dock`, `Ready in <project> on <branch>.`, the five commands to begin with (`/resume`, `/new`, `/changelog`, `/hotkeys`, `/quit`), and `Tip: alt+k opens the command palette.` under it, centered, 63 columns wide or the screen's width; under 34 columns only the title and ready lines show. The version is Gentle Shell's, from the `provisioned` record for this agent home in the `config.json` one folder above it (`4.6.0-main.dd37ffe` reads `4.6.0-main`); without it the title is `Gentle Shell`. It goes through Pi's `ctx.ui.setHeader`: Gentle Shell sets its banner a little after the session starts, which disposes the card, so the card takes the header back on the next microtask (at most 5 times per session). Without that command (no Gentle Shell) there is no card and no `loaded` box: Pi keeps its own header and listing.
13
+ - **Loaded box**: under the welcome card, Pi's list of loaded skills, prompts and extensions (and context files, when Pi lists them) is one box in the same frame (design start-screen/02): `loaded` on its top rule, one row per kind with the kind, its count right-aligned and as many names as fit, cut with `…` (`skills 24 btw, chained-pr, cognitive-doc-design, g…`), and `ctrl+o lists them` on its bottom rule, naming the key Pi binds to `app.tools.expand`: the one Pi's editor holds, live; when Fisi Dock cannot reach the editor's keybindings, the one in Pi's `keybindings.json` (in `PI_CODING_AGENT_DIR`, else `~/.pi/agent`), read once when the box installs, with the legacy `expandTools` id counted and a list of keys joined with `/` (`ctrl+e/alt+o`); with no override there, or a missing or malformed file, Pi's default `ctrl+o`. A key bound to nothing (`[]`) leaves the rule without a hint. A kind with nothing loaded is left out. The box shrinks with the card, and under 34 columns its rows print without a frame or hint. Pressing that key shows Pi's own full listing, grouped by scope with paths, and pressing it again brings the box back. Pi's `[Skill warnings]`, `[Prompt conflicts]`, `[Extension issues]` and `[Theme conflicts]` always print under the box as Pi prints them. The box shows only while the welcome card holds the header (while Gentle Shell's rose briefly replaces it, Pi's listing shows), and only when Pi prints its listing (not with `quietStartup`). How: Fisi Dock finds Pi's loaded-resources container next to the card in the TUI tree and wraps the render of that one instance (never a shared prototype), reading the names from Pi's collapsed sections on each render, so Pi refilling the list on `/reload` keeps the box. `/fisi-dock off` and session shutdown put Pi's own render back. When Pi's tree or its sections have a shape Fisi Dock does not recognize, Pi's listing stays as it is.
14
+ - **Top row**: shows only the project path. Model, effort, context and cost are in the panel and on the prompt box, so nothing repeats.
15
+ - **Prompt box**: Gentle Shell's prompt is closed into a box with the labels on its top rule: `╭─ ✿ waiting for input ──── ● SUPER-YOLO opus-5.5 · high ─╮`, then `│ › … │` rows, then a `╰────╯` bottom rule. The left label is Gentle Shell's own (`waiting for input`, `working…`, or the ODD phase while a request runs); when it is an ODD phase (`exploring…`, `implementing…`, `checking…` and the rest as Gentle Shell writes them) the box puts `ODD ` before it: `╭─ ✿ ODD exploring… ──── ● SUPER-YOLO opus-5.5 · high ─╮`, never for `waiting for input`, `working…` or `queued`. `ODD ` takes 4 columns: the right part still gives way first (it compacts, then drops), and only where even the bare box would not fit with it does the label show without it; the right part is the permission mode after a red dot (only when it is not `NORMAL`, the rule of Gentle Shell's own status bar), then the model and effort. Gentle Shell's own hint on that rule (`esc again to clear`, the vim mode) stays after the labels; its `[ Panel ]` button (the phone sheet with its rail sections, empty while Fisi Dock paints them) is left out, and a tap on the rule row does nothing. The full panel on the phone is `/dock`. The box paints whenever Fisi Dock paints: Gentle Shell's sidebar state on the terminal, in the wide rail chrome and in the narrow fullscreen chrome. How: Fisi Dock wraps Gentle Shell's editor factory (the wrapper carries Gentle Shell's own `gentle-pi.prompt-owner` marker, so Gentle Shell's shutdown and reinstall treat it as their own), renders Gentle Shell's editor four columns narrower and rebuilds only its frame rows: any rows above it and Pi's autocomplete rows under it stay untouched, the editor's invisible cursor markers (APC sequences) count no columns, and mouse clicks are shifted back by the border. Gentle Shell's own work row and agent-question row above the prompt do not show while Fisi Dock empties the `agents` part they read: a question still opens Gentle Shell's own selector, the `agents` card marks it with `!`, and `/gentle:agents` opens the list. The factory it replaced comes back when Fisi Dock unloads. A Gentle Shell update that changes the shape of its panel rule (`─ ✿ label ──── hint ─`), its blank bottom row or its editor's `topRowCount` can break the box: it then falls back to Gentle Shell's own rows and the line below, and `tests/gentle-shell-keys.test.ts` fails against the installed package when `gentle-pi.prompt-owner`, `framePromptLines`, `panelPromptRule` or `topRowCount` are gone.
16
+ - **Prompt box on a narrow rule**: when the width cannot hold the labels beside the idle label (a phone, idle), the label's words drop first and the petal alone keeps them: `╭─ ✿ ──── ● SUPER-YOLO opus-5.5 · high ─╮`, with Gentle Shell's hint after them when it fits too. The idle label is told by how Gentle Shell paints it, not by its words, so a translated, custom or clipped one (`waiting for i…`) gets the same rule: a label Gentle Shell animates (the working scan) is never idle, and one painted whole is idle unless it is `queued`, `working…` or an ODD phase (whole or clipped with `…`) or the editor's scroll indicator (`↑ 3 more`, text out of view). `working…`, `queued`, the ODD phase and the scroll indicator always keep their words. Still too tight, the labels compact step by step instead of dropping: tight separators (`● SUPER-YOLO opus-5.5·high`), then without the effort (`● SUPER-YOLO opus-5.5`), then the mode alone (`● SUPER-YOLO`; the model alone in normal mode), so working on a phone reads `╭─ ✿ working… ─ ● SUPER-YOLO opus-5.5 ─╮` at 40 columns. Each step is tried beside Gentle Shell's hint first (`● SUPER-YOLO INSERT`); with no room for both, the hint wins beside a working label, as it does over the full labels, and our labels win beside the idle one. Only when not even the smallest step fits do the labels drop, then the hint; under 20 columns Gentle Shell's rows stay as they are.
17
+ - **Working label**: the words come from Gentle Shell (`exploring…`, `implementing…`), with `ODD ` before a phase. In the box the color moves across the whole `ODD exploring…` by the clock, at a steady pace, however often the screen is redrawn, and the petal before it turns through Gentle Shell's four flowers (`✿ ❀ ❁ ✾`, in its tones) on the same clock, one flower per wave step (120 ms), each one column wide so nothing shifts. Gentle Shell's `potato` animation keeps its own label and petal, with `ODD ` in the label's gray; under `performance` the box moves the wave and the petal by the clock too, since Gentle Shell's own there step once a second.
18
+ - **Under the prompt** (fallback): when the box could not be installed (no Gentle Shell editor yet, someone else's editor) or did not fit, one line with the same labels: `SUPER-YOLO · opus-5.5 · high` (`opus-5.5 · high` in normal mode). Too narrow for it, the labels compact the same way (`SUPER-YOLO·opus-5.5·high`, `SUPER-YOLO·opus-5.5`, `SUPER-YOLO`) before the line is cut with `…`. The mode, on the box and on the line, comes from Gentle Shell's permission-mode adapter, asked over `pi.events` on `gentle:yolo:host-ui` like its `/gentle:customize` does, and follows `/gentle:mode` and `/gentle:yolo`; without an answer the labels are model and effort only. The prompt editor itself stays Gentle Shell's.
19
+ - **Theme**: ships the `Fisi-Dock` Pi theme with the design's palette and a pink-tinted selection. The first start with Fisi Dock on applies it once and remembers the theme you had, for `/fisi-dock off` to put back; later starts never call Pi's theme setter (see [Turning Fisi Dock off and on](#turning-fisi-dock-off-and-on)). It is also one more choice in `/settings`.
20
+
21
+ ### Narrow screens
22
+
23
+ On narrow or non-fullscreen terminals (a phone over SSH, a split pane) the rail is not shown. Gentle Shell's bars stay as they are, and Fisi Dock adds:
24
+
25
+ - **Top row**: Fisi Dock's own row instead of Gentle Shell's: ` project · branch ▰▰▱▱ 40% $0.012 ●●●`, with the project in bold, the branch in green, a 4-cell context meter in the session colors (teal, amber from 60%, red from 85%) with its percent, the session cost muted (with the cost at 0 and tokens used, `12.4M tok · ≈$38` instead, as in the `cost` row) and one dot per MCP server (green connected, red failing, gray still connecting or unknown). It never shows the model or effort: the prompt box (or, as the fallback, the line under the prompt) shows them. On a tight screen the dots drop first, then the cost, the meter and the branch; the project is cut last. Clicking it does nothing. Without Gentle Shell's sidebar state the row stays Gentle Shell's.
26
+
27
+ - **Strip above the prompt**: one line with what the panel would show and the top row does not, each part in its section color and only when it has data: `✓ ODD 2:45` once the request finished (while a phase is active, the prompt box's working label names it, so the strip does not repeat it), `todo 3/7` (only when no todo card shows, see below) and changed files (`±1 file`). Running agents are not counted here: the agents card lists them. A second line appears only for heads-up warnings (`! 1 commit not pushed · ! ODD plan fisi-dock`). On a tight screen trailing parts drop whole; with nothing to show the strip takes no space. It disappears as soon as the rail shows the panel.
28
+ - **Agents card under the strip**: while an agent, a 4.6.0 subagent task or background job is running (or a subagent task waits for you), an `agents` card framed like the panel sections, with the number running on the right of its top border and one row per running or waiting agent: its turning spinner (an amber `!` for a task that waits for you), name, task (cut to fit) and the time it has been running, `m:ss` (`h:mm:ss` past an hour), ticking each second on the spinner's repaints (with `potato` or `FISI_DOCK_ORBS=off` there is no timer, so it moves only when something else repaints). A job's time counts from the start Gentle Shell reports for it; a job that reports no start counts from when Fisi Dock first saw it running, so one already running when Fisi Dock loaded shows less than its real time. A subagent task's time counts from its first `running` event (until then from its tool call), or from the start in the presence file when it was seeded after a `/reload` (see the `agents` row below). An agent with a model gets the same model label as in the side panel, after its time (`0:42 opus · high`). Up to 4 agents, then `+N more /dock all`. Queued, finished and failed agents are not listed (the side panel still shows them for a while), and with nothing running the card takes no space.
29
+ - **Todo card under the agents card**: while there is a todo list, Fisi Dock's compact `todo` section, framed to the full width: the coral title with `8/10` on the right, `✓ 8 done` with its bar, the active task highlighted with its spinner, the next task and `+N more /dock all`. It keeps a fixed height however long the list is (the side panel lists the tasks instead); `/dock` shows every task. Its header already says `d/t`, so the strip leaves `todo 3/7` out while the card shows. Gentle Shell's own Todos card stays hidden. The card goes away with the strip when the rail shows the panel.
30
+ - **Prompt box**: the same closed box as on wide screens; on a narrow rule its labels compact step by step (see Prompt box on a narrow rule above).
31
+ - **`/dock`**: the side panel over the whole screen, scrolled with the arrows or a swipe (see Commands).
32
+
33
+ ### Wide and narrow screens
34
+
35
+ - **Your messages**: each message you send sits in a gray box with `you` in pink on its top rule (`╭─ you ───╮`), like the prompt box, so it stands apart from tool blocks of the same background. It shows whenever Gentle Shell's sidebar state is on the terminal (fullscreen mode, with or without the wide rail); without Gentle Shell, and on terminals under 10 columns, Pi's own message lines show unchanged.
36
+
37
+ Without Gentle Shell, Fisi Dock paints nothing on its own (no rail parts, no strip, no agents or todo card, no prompt box, no message boxes, and no welcome card or `loaded` box, so Pi keeps its own startup header and listing); `/dock` still opens the panel when asked.
38
+
39
+ ### Panel data
40
+
41
+ | Section | Source |
42
+ |---|---|
43
+ | session | design session-section/02 (Grouped): three groups, each named by a muted label with a short faint stub (`where ──`, `usage ──`, `connections ──`, no full-width rule; a section with one group only has no label), and one muted key column (`project`, `context`, `profile`, `memory`, `mcp`) so every value starts at the same place. **where**: `project fisi-dock main ↑2`, the project folder in bold, the git branch and the commits to push in green (no `↑N` while the heads-up says it). **usage**: the `context` row from Pi: a meter whose filled cells are a heavy `━` in the state color (teal, amber from 60%, red from 85%) and whose empty cells are a thin faint `─`, with a faint `┼` on the cells holding 60% and 85%, then the readout flush right on the same row, `5% · 53.5k/1M` (the percent bold in the state color, the tokens in context and the window size; `5% used` when Pi gives no token counts); the readout keeps at least 13 columns, and when that would leave the bar under 16 cells (the 34-column rail) the bar takes the whole row and the readout moves right-aligned to the row under it; no row when Pi does not know the percent. Then the `profile` row with the cost flush right (below); without a profile the cost keeps a row of its own (`cost $0.012`). **connections**: the `memory` row for Engram (see Memory below), then one row per MCP server, at most 4 rows on the rail (see MCP servers below), or a muted `mcp none configured` without MCP config. The `profile` row: the agent-model profile this session's launches use (`/gentle:profiles`), the label Gentle Shell's own Status section and top row show, which Fisi Dock takes over: `claude` for the global profile, `claude (session)` for one chosen with Use in this session, `team (local)` or `team (repo)` for a pinned one; read from Gentle Shell's in-process profile registries with each Pi read (session start, every turn) and, while no run is active and the panel is on screen, every 10 s; no profile row when the session has no profile or that state cannot be read. The cost: the session cost (`$0.012`), or, when that cost is 0 but the session used tokens (a subscription such as pi-claude-bridge records tokens at cost 0), the session tokens and an API-price estimate: `12.4M tok · ≈$38` (see Tokens and the ≈ estimate below); a long profile is cut before the cost is. The connection rows put the names and the state words in their own columns (names past 12 cells are cut), with one glyph per state so none rests on color alone: green `● connected`, amber `◌ connecting`, red `✗ failed` or `✗ unreachable`, muted `○ not installed`; the gap between name and word closes to one space when two would not fit, and the saved count is the first thing to drop |
44
+ | heads-up | red warnings, drawn only when there is one (at most 5 rows, then `+N more`): other open git worktrees, todo tasks still open after a run ended, unfinished ODD plans in the project's `odd/tasks/*.md`, commits not pushed (replaces the branch's `↑N`), local branches not merged into the default branch |
45
+ | ODD | always drawn: before the first request one muted row `○ ready · phases show while I work`; while a request runs, the timeline of ODD phases with times (latest 6 steps), where the active step shows an animated braille orb in its phase color and its phase name in gray with a white shine sweeping across it, like the prompt box; when the agent's turn ends while this session's subagents still run (queued, running or waiting), the active step stays active and keeps counting until the last of them finishes or the request settles; under each step one gray line, aligned with its name, says what it did: under the active step what its last tool is doing (`editing …/tables/table-row.ts`, `running npm test`), under each finished step a summary (`edited lib/tables/ · 2 files`, `ran npm test · +2 more`, `read 3 files · 1 search`; past 256 different files it says `256+ files`). Paths are relative to the project folder (without regard to case only on Windows drive and network paths); a line too long for the rail keeps its count whole and cuts the path in the middle at a folder (`edited …/tables/ · 12 files`). Commands, paths and labels come from the model, so escape sequences, control characters and bidi overrides are removed before they reach the terminal; once the request is over, one row `✓ last request 2:45 · 4 phases` (the request's wall time and how many phases it went through). `/dock` keeps listing every step after the request |
46
+ | RDD | the session's RDD reviews from Gentle Shell's review events, one row per review, newest last (latest 6, then `+N earlier`), named by the first reviewed file and ` +N` more. A review whose files are not known yet shows as `changes` until they arrive; if the answer is that no review runs (an inspect or status check), that row goes away. On the title's right the RDD switch for the project folder: `on` in green or `off` muted, read from Gentle AI itself with its read-only `gentle-ai review mode status --cwd <folder> --json` at session start and after each turn, one call at a time with a 5 s timeout; a failed, timed-out or unreadable read keeps the last known switch (unknown at first: no switch). The binary is `gentle-ai` on PATH, else the one bundled in the `gentle-pi` package (`.gentle-ai/<version>/gentle-ai.exe` on Windows, `gentle-ai` elsewhere): the package the `gentle-shell` launcher names in `GENTLE_SHELL_CHILD_PACKAGE_INJECTION`, else the global npm one (`%APPDATA%\npm\node_modules\gentle-pi` on Windows; the npm prefix, node's own prefix, `/usr/local`, `/usr` and `~/.npm-global` elsewhere). A running review is highlighted with a turning teal spinner, `reviewing…` (or `fixing…` while findings are fixed) and its time; one waiting for you shows an amber `!` and `needs your OK`; finished ones show `✓ approved`, `✗ outdated · code changed` (changed after approval), `✗ unavailable` or a muted `skipped`, with the local time it ended (`23:05`). Under each review one gray line, aligned with its name, read from the review tools the agent calls (never from the opaque bindings): while it runs, what it is doing (`starting · readability, reliability`, `asks to review · 2 lenses`, `preparing 2 reviewers`, `running 2 reviewers · 1 done`, `fixing · up to 38 lines`, `validating the fix`, `closing · 7 findings, none blocking`, `stopped · 2 findings need your decision`); once it ends with its findings known, what it found (`7 findings · none blocking · 2 lenses`, `3 findings · 1 fix · 2 lenses`, `no findings · 1 lens`); a review that ends without findings known (outdated, unavailable, skipped) has no line. With no review yet: a green `●` and `watching · reviews high-risk changes` when on, `○ off · changes are not reviewed` when off. Not drawn when neither the switch nor any review is known (no Gentle AI) |
47
+ | CI | the GitHub Actions checks of the current branch's last pushed commit, read with `gh` in the session folder (`gh run list --branch <branch> --limit 20 --json …`, the branch from the git read): the commit is the newest run's, one row per workflow of that commit (its newest run). On the title's right the commit's short sha, muted. While a check runs, waits or failed: one row per workflow, sorted by name (at most 6, then `+N more`): a running one highlighted with a turning blue spinner, its name bold, `running…` and the time since it started, ticking with the spinner (when no gh read has succeeded for over 90 s, its time stays at the last successful read and its spinner holds still until the next one); a queued one with a faint `○`, its name muted and `queued` on the right; `✓ lint passed` and `✗ tests failed` (red) with their duration, a failed one with a gray line naming the failed job and its first failed step (`node-22 · Run npm test`, from `gh run view <id> --json jobs`, read again only when the run is updated, for example a re-run; a view that names no failed job leaves no line and is not read again, a failed view is retried on the next read); a cancelled or stale one muted with `-`. Once every check passed, one row `✓ 3 checks passed` (`1 check passed` for one) with the local time of the last update (`14:02`) and a gray line with the workflow names and the longest run (`build, lint, tests · longest 2:41`; only the names when gh gave no durations). gh is read at session start, every 30 s while a check runs or waits, every 3 min otherwise, 5 s and 20 s after a `bash` command with `git push` ends, and when the branch changes to another known branch (the shown checks go at once and the new branch is read; a git read that fails to name the branch changes nothing); never while drawing. Every name from gh is cut to 80 characters and loses escape sequences, control characters and bidi overrides. A failed or timed-out gh read keeps what is shown; no `gh`, no GitHub remote, no workflows or no branch: no section |
48
+ | agents | Gentle Shell's background jobs, from its `gentle-ai:jobs-sidebar` event (finished ones ride the snapshot a short while, as `✓` or `✗`), then Gentle Shell 4.6.0's own subagent tasks (its `subagent_run` / `subagent_continue` tools) as rows of the same shape, in the order they started; at most 4 agents, then `+N more`. A task's state comes from the `gentle-pi:notification:source` events Gentle Shell publishes for this session (`queued` `○`, `running` spinner, `waiting` `!` on a highlighted row when the subagent asks you something, `completed` `✓`, `failed`/`cancelled`/`timed_out` `✗`), ordered by their sequence; its name (the agent) and task text from the tool call's arguments, and its label, model and effort from the tool result (`details.gentleAgents`), which names the task id. A `subagent_run` / `subagent_continue` call in flight is a running row from the moment it starts, before any event, so a running subagent shows even if its events never arrive: the first event of a new task takes the oldest call still waiting (a continue, its own task), the result sets the state while no event has, a refused launch leaves no row, a refused continue puts the row back as it was, and a call whose end was lost goes when the run settles. A task only events name shows as `subagent` with `task <id>` until details arrive. With calls in parallel, two tasks can show each other's text until their results arrive. Its time counts from its first `running` event, until then from the call. Finished tasks stay 60 s, the tail of Gentle Shell's finished jobs, and fold on the next event, tool end or idle refresh. Limits: Gentle Shell's task store is private, so there are no live tokens, cost, turns or tool counts per task; a task started before Fisi Dock loaded (after a `/reload`) shows from one read of Gentle Shell's presence activity file (`<agent home>/gentle-agents/presence/<sha256(session id)>.<incarnation>.activity.json`, agent home `GENTLE_PI_AGENT_HOME`, else `PI_CODING_AGENT_DIR`, else `~/.pi/agent`) at session start, with its own start time; a missing or unreadable file changes nothing. Tool arguments and results are model text, so they are made printable and bounded (escapes, controls and bidi overrides removed, 120 characters). An agent with a model gets a label at the right end of its row: the model family (`opus`, `sonnet`, `haiku`; a model with none of these shows its short name, `gpt-5.1`, any `provider/` prefix and `claude-` dropped) in its effort's color (`low`/`minimal` amber, `medium` blue, `high`/`xhigh`/`max` purple, any other or no effort gray), then ` · <effort>` in gray (`opus · high`); no effort: the family alone; no model: no label. Each agent stays one row: when it does not fit, the task is cut first, then ` · <effort>` drops, then the label. The label never plays the entrance |
49
+ | todo | always drawn: with no todo list or 0 tasks one muted row `○ no tasks · the list shows while I plan` and nothing on the title's right (the todo card above the prompt and the strip's `todo d/t` still show only with tasks). Otherwise Gentle Shell's todo list; on the title's right a progress bar (`▰▱`, up to 10 cells) and `done/total`. Every task in order while there are at most 8 (`✓` done muted, the active one highlighted with its spinner, `○` pending, `◌` blocked, `-` dropped). Past 8, a window of 7 tasks starting at the task before the active one (else the first open task, else the last task), after a `✓ N earlier done` row (`N earlier` when some of them are not done) and before `+N more` with a `/dock all` hint. Without the task list (only counts known yet), at most 4 rows: done count with its bar, active task, next task, `+N more`. `/dock` lists every task (see Commands) |
50
+ | changes | files changed since the last commit, one row per file, the most changed first (lines added plus removed): a symbol for what happened (amber `●` edited, green `+` new, red `-` deleted, blue `→` renamed), the file name in bold, then its folder muted (on a narrow rail the folder is cut before the name). On the right, `+12 -3` lines added and removed for edited files (muted when 0), or `new`, `deleted` or `renamed`. `N to commit` on the title's right. At most 4 files, then `+N more · /dock all`; `/dock` lists every file. With nothing to commit: `✓ everything committed`. Not drawn when git is unknown (not a repository, or not read yet) |
51
+
52
+ Git data (changes, branch, worktrees, unpushed commits, unmerged branches) is read at session start and after every turn and run; ODD plans when a run settles. While no run is active and the panel, the narrow strip or the top row is on screen, an idle session re-reads git, the heads-up git data, the plans, the MCP and Engram state and the model profile every 10 s, through the same one-at-a-time readers as the run triggers, so reads never overlap.
53
+
54
+ ### Tokens and the ≈ estimate
55
+
56
+ Cost and tokens come from the session's assistant messages, the same entries Pi and Gentle Shell sum for the cost. The cost is the sum of `usage.cost.total`; while it is above 0 it shows as `cost $N.NNN`, as before. The tokens are the sum of `usage.totalTokens` (or `input + output + cacheRead + cacheWrite` when a message has no total), shown as `53.5k` or `12.4M`.
57
+
58
+ When the cost is 0 and tokens were used, the row shows the tokens and an **estimate** of what they would cost at API prices, marked with `≈`: whole dollars from $10 (`≈$38`), cents below (`≈$4.27`). It is an estimate, not a bill: a subscription is not charged per token. Each message is priced with Pi's own model prices, never a table in Fisi Dock: `ctx.modelRegistry.find(provider, model)` for the message's own provider and model id, and its `cost` rates (dollars per million tokens for input, output, cache read and cache write, with Pi's price tiers and 1h cache writes at twice the input rate, the same math as Pi's `calculateCost`). pi-claude-bridge registers Anthropic's models under the same ids at price 0, so when the own provider has no price the same id under `anthropic` is used. If any message with tokens has no price, no estimate shows (only the tokens): a partial sum would look like the total.
59
+
60
+ ### Memory (Engram)
61
+
62
+ Engram is not an MCP server: it reaches Pi through the Pi package gentle-engram, which registers tools named `mem_*` (`mem_save`, `mem_search`, `mem_context`, …). The `memory` row reads only what Fisi Dock already has; it starts no process and asks no server:
63
+
64
+ - muted `○ engram not installed` when Pi's tool list (`pi.getAllTools()`) has no tool named `mem_save`;
65
+ - green `● engram connected · N saved` otherwise, where N counts the `mem_save` calls that ended without error in this session (Pi's `tool_execution_end` events, `isError` false; `· 0 saved` before the first one);
66
+ - red `✗ engram unreachable` when the latest `mem_*` call ended with an error; the next `mem_*` call that ends without one makes it connected again.
67
+
68
+ So "connected" means the tools are loaded and the last call did not fail, not that the Engram server answered just now. The tool list is read with every Pi read and by the idle refresh, the calls at each tool end. No row while Pi's tool list cannot be read.
69
+
70
+ ### MCP servers
71
+
72
+ The `mcp` rows list the servers Pi loads, one row each, in config order: the keys of `mcpServers` (or `servers`) in Pi's global `mcp.json` (`~/.pi/agent/mcp.json`, or `$PI_CODING_AGENT_DIR/mcp.json`), then the project's `.pi/mcp.json`. Servers with `"enabled": false` (Pi's switch) or `"disabled": true` are left out; the project file can switch a global server off or on. Only the server names and that switch are read: other fields (commands, URLs, env, headers, auth) can hold secrets and are never read into the panel, logged or stored. The files are read at session start.
73
+
74
+ Pi connects the servers itself, in the background; Fisi Dock only looks. Pi registers every tool of a connected server as `mcp__<server>__<tool>` in the namespace `mcp__<server>` (with `-` in the server name replaced by `_`), also when the tools are only reachable from codemode, and keeps them as hidden tools when a server drops or is switched off in `/mcp`. So a server is:
75
+
76
+ - **green `● connected`** when Pi's tool list (`pi.getAllTools()`) has at least one visible tool with that name prefix or namespace;
77
+ - **amber `◌ connecting`** (unknown) during the first 10 s of the session (servers connect late), when it has only hidden tools, or when Pi's tool list cannot be read;
78
+ - **red `✗ failed`** (failing) when, 10 s after the session started, it has no tools at all.
79
+
80
+ The rail shows at most 4 `mcp` rows. With 5 servers or more, 3 of them keep a row, the problems first: failed, then connecting, then connected, each state in config order; the fourth row sums up the rest under the names: `+7 more · 2 connecting · 5 connected`, `+N more` muted and each count in its state's color, failed, connecting and connected in that order and only the states that occur. When the row is too narrow the counts drop from the right, then `+N more` stands alone (the 34-column rail), then it is cut. With 4 servers or fewer every one has its row, in config order, and there is no summary. `/dock` lists every server, in config order. The summary is a session row like any other on a short screen.
81
+
82
+ With no `mcp.json` (or no enabled server in it) the row says so, muted: `mcp none configured`.
83
+
84
+ The state is refreshed with every Pi read (each turn and run) and by the idle refresh. Fisi Dock never handles Pi's `mcp_servers_change` event (handling it would make Fisi Dock the MCP connector). Pi reads a project's `.pi/mcp.json` only for trusted projects; Fisi Dock cannot see the trust setting, so an untrusted project's servers show red.
85
+
86
+ An ODD plan counts as unfinished when its `## Tasks` section has a task line not marked done (`[x]`, "done", or a recorded commit; "Commit: pending" is open). Files without a `## Tasks` section and files over 200 KB are skipped. To see the heads-up rows for any folder without Pi: `node scripts/heads-up.ts <folder>` (read-only).
87
+
88
+ The ODD orb follows Gentle Shell's animation level (`/gentle:animations`, read from its `animations.json` at each new request): `quality` and `performance` at full speed, `potato` a still frame and a still gray phase name with a once-per-second refresh. To force the still orb: set `FISI_DOCK_ORBS=off` before starting Gentle Shell.
89
+
90
+ The running spinner on the active todo task and on running agents (side panel, todo card, agents card and `/dock`) turns with the clock: `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`, one frame every 80 ms, repainted by a timer that runs only while an agent or job is running, or a todo task is active while a run is active. A task left in progress after the run settled shows the still `⠹`. It follows the same animation level (read when work starts): `potato` and `FISI_DOCK_ORBS=off` show a still `⠹` with no timer. Done (`✓`), queued (`○`), waiting (`!`) and failed (`✗`) rows do not move.
91
+
92
+ A row that appears plays a short entrance: a newly running agent (`agents`), the todo task that becomes active (`todo`, also on the todo card and in `/dock`; the agents card plays it for a new running agent too), a new active ODD step (`ODD`) and a new review row (`RDD`). For 3 steps of 75 ms the row and its glyph flash bold in the section color (lilac, coral, amber, rose), fading to the row's own colors; then one white shine (`#ffffff`, `#c8c8c8`, `#9a9a9a`) crosses its text once, one letter per step, and the row looks as before (the active ODD step then goes back to its gray shimmer). It lasts about a second, a little longer for long text. Only the new row moves; rows already on screen when Fisi Dock loads, `changes`, `heads-up`, the strip and the top row never play it. While an entrance plays, the spinner's timer repaints at the 75 ms step and stops when nothing runs or enters. Only colors change, so no row gets wider. With `potato` or `FISI_DOCK_ORBS=off` the row simply appears.
93
+
94
+ The wordmark reads GENTLESHELL, the words joined and told apart by color: GENTLE gray, SHELL in the pink of Gentle Shell's Gentleman-Sexy theme (`#F43888`). It is drawn in braille dots, GENTLE in a gray fade and SHELL from that pink to the theme's deep pink (`#BF0F50`), no shadow. At 51 columns or more (Gentle Shell fisi/custom's 55-column rail) it draws the wide 51-column mark; from 45 to 50 columns, the official rail's 47 usable columns included, the 45-column compact mark (the same G, N and L, a narrower E, T, S and H). Narrower rails show it as one bold text row, its letters one column apart (`G E N T L E S H E L L`, 21 columns); from 11 to 20 columns the letters join (`GENTLESHELL`); below 11 columns nothing. The mark is centered over the section frames, at most two columns in.
95
+
96
+ Fisi Dock reads Gentle Shell only through its shared sidebar state (`Symbol.for("gentle-pi.experimental-sidebar.state")` and `.cache`), its ODD phase registry and its `pi.events` channels; nothing is imported from the `gentle-pi` package, so an update cannot break Fisi Dock's loading. `tests/gentle-shell-keys.test.ts` checks the installed package still defines those keys. The package it checks is `GENTLE_SHELL_DIR` when set, else the one Gentle Shell itself loads: the package the `gentle-shell` launcher names in `GENTLE_SHELL_CHILD_PACKAGE_INJECTION` (inside a session), else the launcher's own, found from the `gentle-shell` on PATH (a pnpm or npm shim, or npm's link) up to its package; else `gentle-pi` in the global npm root (`npm root -g`). Only a folder whose `package.json` is named `gentle-pi` counts, and when several are found the version provisioned for the agent home in `~/.gentle-shell/config.json` (`GENTLE_SHELL_CONFIG` when set; the home is `GENTLE_PI_AGENT_HOME`, else `PI_CODING_AGENT_DIR`, else `~/.gentle-shell/agent`) wins, else the first found. With none (CI) those checks are skipped.
97
+
98
+ `tests/configs.test.ts` drives Fisi Dock the way Pi and Gentle Shell call it, in memory, under simulated user configurations: a translated idle and working label, no Engram (and Engram failing, then back), ten MCP servers, Vim's `INSERT`/`NORMAL` hint, a 30-column screen, a remapped or unbound expand key, all of them at once, and no Gentle Shell. Every surface (welcome card, loaded box, rail panel, top row, strip, prompt box, line under the prompt, `/dock`) is rendered at every width from 0 to 140, wide and narrow: nothing throws and no line passes the width. Each test points Pi's and Gentle Shell's dirs at a fresh temp folder, so your own configuration is never read.
99
+
100
+ ## Commands
101
+
102
+ | Command | What it does |
103
+ |---|---|
104
+ | `/dock` | Shows the full Fisi Dock side panel over the whole screen, live, exactly as the rail draws it: two rows down from the top (as the rail sits under the top row and its gap), edge to edge with one column of margin each side (at most 80 columns wide; a wider screen centers it), no frame around it, and the same colors as the side panel (no background of its own: it covers the conversation behind it with the terminal's own background). The last row says `Esc to close` and, while the panel is taller than the screen, `↑↓ scroll`. ↑/↓, Page Up/Page Down and the mouse wheel scroll it; on a phone terminal that sends swipes as the wheel (mouse reporting), a finger swipe scrolls it too. Taps do nothing. Esc closes it and returns to the prompt. Useful on narrow screens, works on wide ones too. Here the todo section is not capped: it lists every task in list order, done ones with a green `✓`, the active one highlighted with its spinner, pending ones with `○`, blocked ones with an amber `◌` and dropped ones muted with `-`. While Fisi Dock is off it only says so. |
105
+ | `/fisi-dock on` \| `off` | Turns Fisi Dock on or off without uninstalling it, remembered across restarts (see below). `/fisi-dock` alone opens a picker titled with the current state (`Fisi Dock is on`), the change listed first, so Enter switches it and Esc changes nothing (without a picker it only says whether it is on); typing `/fisi-dock ` with the space also suggests `on` and `off`. Any other argument shows the usage and changes nothing. |
106
+
107
+ ## Turning Fisi Dock off and on
108
+
109
+ Pi cannot unload an extension in the middle of a session, so `/fisi-dock off` puts Fisi Dock to sleep instead, the same way it unloads: Gentle Shell gets back its rail Status section and top row, its `todo`, `jobs` and `agents` sections and its status bar, its prompt editor (the closed box goes) and the lines Fisi Dock hides; the start screen goes back to Pi's own header (Gentle Shell's rose returns on the next start or `/reload`); the panel, the strip, the agents and todo cards and the line under the prompt stop painting, your messages go back to Pi's own lines, and Fisi Dock's timers and readers stop. `/dock` then only says Fisi Dock is off. `/fisi-dock on` takes everything over again, as at the start of a session.
110
+
111
+ The choice is saved in `<Pi agent dir>/fisi-dock/state.json` (`PI_CODING_AGENT_DIR`, else `~/.pi/agent`; Gentle Shell sets `PI_CODING_AGENT_DIR` to its home, so `~/.gentle-shell/agent/fisi-dock/state.json` by default and `~/.pi/agent/fisi-dock/state.json` with `--link`), for example `{ "enabled": false, "theme": "dark", "themeApplied": true }`, outside any repository. While it says off, every new session starts with Fisi Dock asleep until `/fisi-dock on`; a missing or unreadable file means on.
112
+
113
+ The theme follows the switch: on remembers the theme you had (Pi's `ctx.ui.theme.name`) in that same file and sets `Fisi-Dock`; off puts the remembered theme back. When the theme is already `Fisi-Dock` as on runs, the one remembered before is kept. A theme chosen as `Fisi-Dock` in `/settings` (not through on) remembers nothing new, so off then gives back the theme remembered before, else `Gentleman-Cute`. Removing Fisi Dock leaves `state.json` and Pi's theme setting as they are; a theme setting of `Fisi-Dock` without the theme loaded makes Pi fall back to its `system` theme. With nothing remembered, or when the remembered theme is gone (Pi no longer knows it, so it is not tried), off sets Gentle Shell's own theme, `Gentleman-Cute`, and says so; if that one is missing too, the theme stays as it is and off warns. It goes through Pi's own theme setter (`ctx.ui.setTheme`), which also saves it as your Pi theme setting, as `/settings` would.
114
+
115
+ The first start applies the theme once. A session start with Fisi Dock on, a UI and Gentle Shell loaded (its `gentle:banner` command; plain Pi keeps its theme and the step stays pending), while the state file has no `"themeApplied": true` (a fresh install, or a state from before this step), first saves the theme in use to the file (not `Fisi-Dock` itself; with no theme name, the one remembered before is kept), then sets `Fisi-Dock`, writes `"themeApplied": true` with the theme, and notifies `Fisi Dock applied its theme · /fisi-dock off puts your theme <name> back` (`theme Gentleman-Cute` with nothing remembered). With `Fisi-Dock` already in use it only writes the flag, with no notice. It never repeats, so a theme picked later in `/settings` stays on every following start. The flag stays unwritten, so the next start tries again, when Pi does not know `Fisi-Dock` (`ctx.ui.getTheme`) or its setter fails or throws. When the state file cannot be written the theme is not changed, since the one you had could not be given back. A delegated child session (`GENTLE_PI_AGENTS_CHILD=1`) does none of it, and neither does a start while the state says off: there `/fisi-dock on`, once it set `Fisi-Dock`, writes the flag. Off keeps the flag; deleting `state.json` makes the next start apply the theme again.