Skip to content

docs(tui): record VS Code terminal environment for the parity matrix - #490

Draft
PranavD2905 wants to merge 7 commits into
Observal:mainfrom
PranavD2905:docs/vscode-terminal-evidence
Draft

PranavD2905 wants to merge 7 commits into
Observal:mainfrom
PranavD2905:docs/vscode-terminal-evidence

Conversation

@PranavD2905

Copy link
Copy Markdown

Purpose

Start the VS Code row of the manual parity matrix (#466, part of #42). This PR records the test environment. It does not record any manual results yet.

Fixes

Refs #466. This does not close the issue: the manual scenario has not been run.

Approach

Updates only the VS Code row in docs/terminal-compatibility.md:

  • Environment: VS Code 1.134.0, zsh 5.9, macOS 26.5.2 arm64, no multiplexer, default image mode (metadata expected).
  • Every result column says "Not run yet" instead of a result. No column is reported as passing.

Opened as a draft. I will add real results, failure notes, and privacy-safe screenshots after I run the manual scenario in the VS Code integrated terminal. The window size will be recorded then.

How was this tested?

  • pnpm format:check: passed.
  • pnpm install --frozen-lockfile and pnpm build: passed.
  • axl doctor on this machine: native seatbelt sandbox available.
  • Not run: the manual scenario (resize, Unicode multiline input, paste, keyboard fallbacks, dropped images, fullscreen, disconnect recovery, restoration, suspend). reuse lint was not run because REUSE is not installed locally.

Checklist

  • I reviewed the complete diff.
  • I added or updated the smallest relevant test for behavior changes. (Docs only.)
  • I ran the relevant formatting, lint, type-check, test, boundary, and license checks. (pnpm format:check only; reuse lint not run.)
  • Every new file has SPDX metadata, directly or through REUSE.toml. (No new files; contributor SPDX line added.)
  • Every commit has a matching DCO Signed-off-by trailer.
  • UI changes include screenshots attached to the pull request, not committed to the repository. (Pending manual run.)

AI assistance

  • Generative AI materially assisted this change. Tool and model/version: Claude Code (Claude Opus 5.5)
  • I manually reviewed, understood, and tested the generated work.

Haz3-jolt and others added 7 commits October 4, 2026 15:05
An axolotl above the composer that shows what the harness is doing, off by
default and turned on with /mascot. It maps session events onto states
instead of inventing its own: waking on attach, typing beside the cursor,
thinking on a prompt, working while tools run, file_change on a write,
success at the end of a turn, ask while a permission or interaction request
waits on the user, blocked on a sandbox violation, nod on a queued message,
compact during /compact, error then severed when a turn fails, dead on an
interrupt, and resume on a retry.

The player only keeps time and names the frame, the director maps events
to states, and the actor decides where the sprite sits, so each is tested
on its own. It draws with the best the terminal offers: Kitty graphics,
one placement per frame; sixel, where the terminal reports it in its device
attributes and answers with its cell size, four rows tall and redrawn in
one write from the strip's last line; and a half-block text pack 12 rows
tall everywhere else, which every font can draw, converted once to the
nearest of the 256 xterm colours when the terminal lacks 24-bit colour.
Its strip keeps its height at every sink so the composer never moves. The composer's border paints its own background to hide a Kitty
image, and the line runs through the middle of that row, so the build
measures the clear space under each animation and the renderer ends the
image on the line. Typing rests its arms there with the body behind the
composer, and the working patrol only travels once it swims.

Four colours ship, /mascot Pink, Albino, Purple or Deep_Sea, as palettes
over one indexed atlas: the client swaps the atlas's palette chunk, the
text pack's colour codes, or the sixel colour table, so one set of art
serves every colour and the assets are under 1 MB.

docs/terminal-compatibility.md lists what each terminal gets and what has
been verified. The art is our own and Apache-2.0. An earlier draft used art
from a purchased pack whose terms did not allow publishing it; this branch
was rebuilt on main so no commit in it holds any of that art.

Setup is numbered and only the latest is installed, so a second /mascot or
a display mode change cannot be undone by a setup finishing late. Pasted
text is left out of the terminal report filter, and focus and mouse reports
do not count as typing. Shutdown clears the mascot state before writing the
image clear and collects a failing write with its other shutdown failures.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
…he SDK

The player, the event director, and the actor hold no terminal or Node code.
They decide which frame plays, which state a session event selects, and where
the sprite sits, which every client needs to show the same mascot. Moving them
into packages/sdk lets the web client use them without a second copy, and the
terminal now imports them from @axl/sdk.

Their tests move with them. The terminal's drawing code and its tests stay in
packages/tui.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
The web client shows the same axolotl above the composer, off by default and
turned on with /mascot. It uses the SDK's player, director, and actor, so
canonical events pick the same states as in the terminal: thinking on a
prompt, working while tools run, ask while a request waits, and so on. The
composer's keystrokes drive typing, and the actor places the sprite in the
same 9 by 18 pixel cells.

The canvas draws frames from the Pink atlas. Other colours swap the palette in
the decoded pixels, and the other facing mirrors the canvas, so one atlas
serves every colour. /mascot Pink, Albino, Purple, or Deep_Sea picks a colour
and /mascot sas plays the one-shot. The mascot is presentation only: it reads
events and sends nothing to the daemon. A load failure turns it off and shows
the error. Reduced motion keeps the sprite in place.

The manifest and atlas are copies of the terminal's assets, and a test keeps
them equal.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
The model picker listed every catalog model, including those of providers
with no credentials. Choosing one made the daemon refuse the selection with
an authentication error, and because the picker callback did not await the
command, the rejection ended the terminal client.

As in pi, only models with configured authentication are offered now. The
terminal asks for each provider's authentication status instead of trusting
the listing, which carries only the last known state. /model shows "No models
available" when none are logged in, and naming a model of a logged out
provider says to use /login. The web picker filters the same way through a new
authenticated flag on ModelChoice, and keeps the other models so a session
already on one still shows its name and thinking levels.

Command failures raised from picker callbacks now reach the notice line
instead of escaping.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
…he composer

The mascot is on by default in both clients and /mascot saves the choice and
the colour: the terminal in settings.json, the browser in the host's web
preferences. A saved off stays off after a restart.

A Kitty image can only be hidden under the composer's top border if that row
is painted a colour the terminal does not treat as its default. The row was
painted near black, which showed as a dark band across the terminal wherever
the background was lighter. The terminal is now asked for its background with
OSC 11, and the row is painted that colour with one level of blue added, which
cannot be told from unpainted. A terminal that does not answer within 400 ms
keeps the near black row.

The web client rejects a colour the manifest does not have before saving it.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
The terminal session now takes the cell size reply out of the input and
reports it, so the mascot's own parsing never saw it and sixel was never
chosen. The mascot reads that size and rebuilds as sixel when it arrives.

The image clear for a dialog is joined to the first row of the frame instead
of being a row of its own, which shifted the dialog's cursor and clipping by
one.

With reduced motion the web mascot draws one still pose per state instead of
looping frames, and the docs describe the mascot as on by default and
remembered in both clients.

Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
Signed-off-by: PranavD2905 <pranavdeshpande2005@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 4, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants