---
title: Inbuilt Terminal
---

# Inbuilt Terminal

## What it is

A real shell terminal inside Omniscio, scoped to a project. **In-development** feature — visible only when Labs → **Inbuilt terminal** is on (or the env var `AMC_SHOW_INBUILT_TERMINAL=1` is set).

## Where to find it

Click the **terminal icon** in the sessions sidebar header to open a terminal in the current project's folder. While a terminal is focused, **Ctrl/Cmd+T** opens another. Saved snippets are managed in **Settings → search "Terminal snippets"** — a deep-link-only page, since the feature is unreleased.

## How it behaves

### What it does

- **Open a terminal in the current project's folder** by clicking the terminal icon in the sessions sidebar header (or **Ctrl/Cmd+T** when a terminal is focused).
- Runs whatever shell your OS picks up (`$SHELL` on macOS/Linux; on Windows, PowerShell 7 `pwsh.exe` when it's installed, else Windows PowerShell `powershell.exe`, else `cmd.exe`). The Windows shell is **resolved on PATH** before use, so an uninstalled shell is never handed to node-pty (that mismatch was the "File not found:" spawn crash). Renders via `xterm.js`; the PTY is `node-pty` in the main process.
- **Persistent scrollback** — the last 100 KB of output survives closing and reopening the panel. Restored via `@xterm/addon-serialize` on mount.
- **Ctrl/Cmd+K** opens a **snippet palette** — fuzzy-search over your saved snippets, arrow keys navigate, Enter pastes the command into the terminal (paste-only; you press Enter yourself to run it).
- **Save a snippet** with the bookmark-icon button in the panel header — opens a dialog with Name + Command fields.
- **Ctrl/Cmd+F** reveals a Find bar over the terminal (uses xterm's SearchAddon).
- **Live theme rebind** — switching light/dark or changing the accent color re-applies the terminal theme without recreating it.

### Manage snippets

Settings → search "**Terminal snippets**" (deep-link only — no nav row while the feature's unreleased). Full CRUD list: Add / Edit / Delete rows. Deletes go through `ConfirmDialog` and register an undo via `useUndoStore` (a toast surfaces the restore action).

Snippets are user-wide (one shared list across every project). Storage: `terminal_snippets` table (`id`, `name`, `command`, `position`, `is_deleted`, timestamps).

### Command blocks (v3)

**Additional gate**: command blocks require BOTH `AMC_SHOW_INBUILT_TERMINAL=1` AND `AMC_SHOW_INBUILT_TERMINAL_BLOCKS=1` (or Labs → **Inbuilt terminal blocks**). The block overlay is completely invisible unless both flags are on.

### What it does

Every command you run in the terminal gets a "block" — a visual unit in the gutter to the left of the xterm viewport:

- A **green check** or **red X** gutter dot marks exit-code 0 vs non-zero.
- **Hovering** the gutter reveals three icon buttons: **Fold** (collapse the block's output rows), **Copy** (copy just that command's output to the clipboard), and **Re-run** (types the original command text at the prompt — you press Enter yourself; it never auto-executes).
- Blocks are **fully persistent**: they survive closing and reopening the terminal panel, restoring with the same fold/copy/re-run affordances. The restore sequence waits for both the scrollback content and the block metadata before mounting (see Invariant 3 below).

### Shell integration — how it works

When the `inbuilt-terminal-blocks` feature is visible, `TerminalPtyService.spawn()` injects per-shell env vars that load bundled shell-init scripts **without touching any user rc file**:

| Shell | Mechanism                                                                                                                                    | User rc                   |
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| zsh   | `ZDOTDIR` → scratch tempdir whose `.zshrc` sources Omniscio's init, then Omniscio's init sources the real `~/.zshrc` via `$AMC_USER_ZDOTDIR` | read-only (never written) |
| bash  | `BASH_ENV` → Omniscio's init script, which sources `~/.bashrc` via `$AMC_USER_HOME`                                                          | read-only                 |
| pwsh  | `AMC_USER_PROFILE` → Omniscio's init script; `$PROFILE.ps1` sourced from inside the init                                                     | read-only                 |

Omniscio's init scripts emit OSC 133 sequences (`\x1b]133;A\x07`, `B`, `C`, `D;<exit>`, `P;cwd=<path>`) around each command lifecycle. **Nothing writes to `~/.zshrc`, `~/.bashrc`, or `$PROFILE.ps1`.**

### Data flow

```
Shell (zsh/bash/pwsh)
  └─ emits OSC 133 sequences on PTY output stream
       │
       ▼
terminal-osc133-parser.ts (Task 4)
  └─ strips OSC 133 markers from stream (xterm never sees \x1b]133)
  └─ emits BlockEvent[] (prompt-start, command-start, command-end, cwd-change)
       │
       ▼
terminal-block-processor.ts (Task 5)
  └─ accumulates BlockEvent[] into PartialBlock drafts → seals TerminalBlockRow on command-end
       │
       ▼
terminal-session-manager.ts (Task 6)
  └─ persists sealed blocks to terminal_blocks (SQLite, additive migration)
  └─ emits TERMINAL_BLOCK_EVENT push to renderer
       │
       ▼
TerminalBlockOverlay.tsx (Task 7)
  └─ subscribed via usePushListener(TERMINAL_BLOCK_EVENT)
  └─ positioned absolutely over xterm viewport
  └─ renders TerminalBlockGutterRow per block (exit-code dot + fold/copy/re-run actions)
```

### Key files

- **Main/backend**: `src/main/services/engines/terminal-osc133-parser.ts` (pure OSC 133 parser), `src/main/services/engines/terminal-block-processor.ts` (draft accumulator → sealed blocks), `src/main/services/engines/terminal-shell-init.ts` (resolve bundled init script path by shell), `src/main/services/engines/terminal-shell-init-env.ts` (build per-shell env map for PTY spawn), `src/main/db/queries-terminal/blocks.ts` (SQLite persistence), `src/main/ipc/terminal-blocks-handlers.ts` (Zod-validated IPC: `TERMINAL_BLOCKS_LOAD`, `TERMINAL_RUN_COMMAND_IN_SESSION`).
- **Renderer/UI**: `src/renderer/src/features/terminal/TerminalBlockOverlay.tsx` (overlay container, subscribes to push events), `src/renderer/src/features/terminal/TerminalBlockGutterRow.tsx` (per-block gutter row + hover actions), `src/renderer/src/features/terminal/terminal-blocks-store.ts` (Zustand store for block state), `src/renderer/src/features/terminal/useTerminalSession.ts` (mounts blocks alongside scrollback on open).
- **Shell scripts**: `resources/terminal-shell-init/amc-init.{zsh,bash,ps1}` — bundled init scripts; copied to the ZDOTDIR/BASH_ENV tempdir at spawn time.
- **Migration**: the additive `terminal_blocks` table migration (`id`, `session_id`, `block_index`, `start_row`, `end_row`, `command`, `exit_code`, `cwd`, timestamps — no `is_deleted`; blocks are append-only).

### IPC channels (v3 additions)

- `TERMINAL_BLOCKS_LOAD` — renderer hydrates its per-session block store on mount.
- `TERMINAL_BLOCK_EVENT` (push) — main pushes a `TerminalBlockEvent` to the renderer whenever a block seals or updates.
- `TERMINAL_RUN_COMMAND_IN_SESSION` — "Re-run" click: main calls `terminalPtyService.write(sessionId, command)` with NO trailing newline (user must press Enter).

### Known limits + roadmap

- Only one terminal per session row for now (open multiple terminals by creating multiple terminal sessions — sidebar handles them like any other session).
- No SSH profile manager, no split panes, no session recording (roadmap v4).

## For agents

### Where the code lives

- **Main / backend**: `src/main/services/engines/terminal-pty-service.ts` (node-pty lifecycle), `src/main/services/engines/terminal-session-manager.ts` (session-manager wrapper), `src/main/db/queries-terminal/{scrollback,snippets}.ts` (persistence), `src/main/ipc/terminal-{handlers,scrollback-handlers,snippet-handlers}.ts` (Zod-validated IPC).
- **Renderer / UI**: `src/renderer/src/features/terminal/{TerminalPanel,TerminalCommandPalette,SaveSnippetDialog,TerminalSearchOverlay,useTerminalSession,terminal-{palette,search,new,snippets}-store}.tsx?`.
- **Settings CRUD**: `src/renderer/src/features/settings/sections/terminal-snippets/TerminalSnippetsSettings.tsx`.
- **Scoped keyboard dispatchers**: `src/renderer/src/hooks/keyboard-shortcuts/{terminal-palette,terminal-search,terminal-new}.ts` — Ctrl+K / Ctrl+F / Ctrl+T are dispatched BEFORE the general binding lookup so they beat `globalSearch` etc.; the combos are hardcoded (not user-rebindable), mirroring the Team Chat quick-switcher pattern.

### IPC channels (all Zod-validated, `wrapHandler`-wrapped)

- Session lifecycle: `SESSION_CREATE_TERMINAL`, `TERMINAL_INPUT`, `TERMINAL_RESIZE`, `TERMINAL_KILL`, `TERMINAL_OUTPUT` (push).
- Scrollback: `TERMINAL_SCROLLBACK_SAVE`, `TERMINAL_SCROLLBACK_LOAD`.
- Snippets: `TERMINAL_SNIPPET_LIST`, `TERMINAL_SNIPPET_CREATE`, `TERMINAL_SNIPPET_UPDATE`, `TERMINAL_SNIPPET_DELETE`.

## Related

Where Omniscio runs shell commands on your behalf in general — and what it refuses — is described under the app's shell settings.
