Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/tui-lock-v2/120x40/init-agents.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/tui-lock-v2/40x12/init-agents.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions docs/media/tui-lock-v2/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ captures use `MinimalSessionView` plus lock flags (`computer_held`,
`show_computer_default`, `offline_held`, `rate_limit_held`) so MockTerminal
matches live chrome.

- Boards: [`index.md`](index.md) — 89 boards at 120×40, 43 of them also at 40×12 (132 PNGs).
- Boards: [`index.md`](index.md) — **95** runtime boards at 120×40, 49 of them also at 40×12. Designer PNG files under `{40x12,120x40}/` from other PRs are not rewritten; new scenes are captured with `generate_tui_lock_screenshots --v2 --only`.
- Grids: `txt/<size>/<board>.txt` — the exact character grid of every board (diff a
`MockTerminal` capture against these).
- Renderer: `tools/render_lock_v2.py` + `tools/boards.py` (Python 3 + Pillow, IBM Plex Mono
Expand Down Expand Up @@ -414,9 +414,10 @@ Narrow: no bars, `used / total pct%`.
| slash-palette / slash-model-typed | `slash-palette` (`/goal` after `/plan`), `slash-model-typed` |
| goal-chip (active / paused / done / budget / blocked) | `goal-chip-active`, `goal-chip-paused`, `goal-chip-done`, `goal-chip-budget`, `goal-chip-blocked` |
| model-effort-low·medium·high / model-list-hover | `model-list`, `model-list-hover`, `model-effort-high`, `model-effort-medium`, `model-effort-low`, `model-effort-hover` |
| settings-appearance / mouse / row-hover / search / theme-submenu | `settings-appearance`, `settings-mouse`, `settings-row-hover`, `settings-search`, `settings-theme-submenu` |
| settings-appearance / mouse / row-hover / search / theme-submenu | `settings-appearance`, `settings-mouse`, `settings-row-hover`, `settings-search`, `settings-theme-submenu`, `theme-picker` |
| theme / handoff / fork / init / commands / hooks | `theme-picker`, `handoff-confirm`, `session-fork`, `init-agents`, `custom-commands`, `hooks-lifecycle` |
| mode chips (Shift+Tab) | `mode-agent`, `mode-plan`, `mode-ask`, `mode-bash` |
| permissions / mcp / plugins / usage-quota / sandbox / cloud | `permission-prompt`, `permission-prompt-hover`, `permissions-picker`, `mcp-servers`, `mcp-drop`, `plugins`, `usage`, `quota-exhausted`, `sandbox`, `sandbox-deny`, `cloud-handoff`, `computer-disconnected`, `computer-cloud-default` |
| permissions / mcp / plugins / usage-quota / sandbox / cloud | `permission-prompt`, `permission-prompt-hover`, `permissions-picker`, `mcp-servers`, `mcp-drop`, `plugins`, `usage`, `quota-exhausted`, `sandbox`, `sandbox-deny`, `cloud-handoff`, `handoff-confirm`, `computer-disconnected`, `computer-cloud-default` |
| diagnostics red/amber · interrupt/stopped | `diagnostics`, `interrupt-stopped`, `error-unavailable`, `offline`, `rate-limit` |
| markdown table · diff hunk · code fence | `md-table`, `diff-hunk`, `edit-collapsed`, `code-fence`, `tool-tiles`, `tool-tiles-collapsed`, `shell-running` |
| login / first-run | `login`, `login-waiting`, `login-success`, `login-error`, `first-run-tips` |
Expand All @@ -428,7 +429,7 @@ Narrow (40×12) set: `welcome-cortex`, `welcome-agent`, `first-run-tips`, `sessi
`session-thinking-live`, `session-assistant`, `session-optin`, `composer-empty`, `composer-typing`, `composer-hover`,
`tokens-topright`, `compact-chat`, `slash-palette`, `goal-chip-active`, `goal-chip-paused`, `goal-chip-done`,
`goal-chip-budget`, `goal-chip-blocked`, `slash-model-typed`, `model-list`, `model-effort-high`,
`settings-appearance`, `settings-mouse`, `settings-row-hover`, `settings-theme-submenu`, `mode-plan`, `mode-ask`,
`settings-appearance`, `settings-mouse`, `settings-row-hover`, `settings-theme-submenu`, `theme-picker`, `session-fork`, `init-agents`, `custom-commands`, `hooks-lifecycle`, `handoff-confirm`, `mode-plan`, `mode-ask`,
`permission-prompt`, `mcp-servers`, `usage`, `diagnostics`, `interrupt-stopped`, `offline`, `rate-limit`, `computer-disconnected`, `computer-cloud-default`, `diff-hunk`, `login`, `shortcuts-overlay`,
`consent-local-tools`, `composer-file-chip`, `undo-sheet`.

Expand Down
10 changes: 7 additions & 3 deletions docs/media/tui-lock-v2/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ Regenerate: `python3 tools/render_lock_v2.py --index` (fetches IBM Plex Mono on
| `goal-chip-budget` | Composer goal chip — `Goal · budget` (budget_limited), text-only | [120x40](120x40/goal-chip-budget.png) | [40x12](40x12/goal-chip-budget.png) |
| `goal-chip-blocked` | Composer goal chip — `Goal · blocked`, text-only | [120x40](120x40/goal-chip-blocked.png) | [40x12](40x12/goal-chip-blocked.png) |
| `slash-model-typed` | `/mod` typed — banner green matched chars, ghost completion | [120x40](120x40/slash-model-typed.png) | [40x12](40x12/slash-model-typed.png) |
| `theme-picker` | `/theme` — Cortex Night / Cortex Day / Ocean Dark / Monokai | [runtime 120x40](runtime/120x40/theme-picker.png) | [runtime 40x12](runtime/40x12/theme-picker.png) |
| `session-fork` | `/fork` — fork this session or stay | [runtime 120x40](runtime/120x40/session-fork.png) | [runtime 40x12](runtime/40x12/session-fork.png) |
| `init-agents` | `/init` — AGENTS.md from the built-in project template | [120x40](120x40/init-agents.png) · [runtime](runtime/120x40/init-agents.png) | [40x12](40x12/init-agents.png) · [runtime](runtime/40x12/init-agents.png) |
| `custom-commands` | `.cortex/commands` + repo `SKILL.md` | [runtime 120x40](runtime/120x40/custom-commands.png) | [runtime 40x12](runtime/40x12/custom-commands.png) |
| `hooks-lifecycle` | `/hooks` — pre_tool_use / post_tool_use / stop / session_end | [120x40](120x40/hooks-lifecycle.png) · [runtime](runtime/120x40/hooks-lifecycle.png) | [40x12](40x12/hooks-lifecycle.png) · [runtime](runtime/40x12/hooks-lifecycle.png) |
| `model-list` | `/model` — Cortex Mini 1 · Cortex 1 · Cortex Max 1 | [120x40](120x40/model-list.png) | [40x12](40x12/model-list.png) |
| `model-list-hover` | Model list with mouse over row 3 | [120x40](120x40/model-list-hover.png) | — |
| `model-effort-high` | Effort radios — High focused | [120x40](120x40/model-effort-high.png) | [40x12](40x12/model-effort-high.png) |
Expand Down Expand Up @@ -85,6 +90,7 @@ Regenerate: `python3 tools/render_lock_v2.py --index` (fetches IBM Plex Mono on
| `sandbox` | `/sandbox` — filesystem / network / escalation | [120x40](120x40/sandbox.png) | — |
| `sandbox-deny` | Sandbox blocked a command — red title, radios | [120x40](120x40/sandbox-deny.png) | — |
| `cloud-handoff` | `&` handoff to Cortex Cloud | [120x40](120x40/cloud-handoff.png) | — |
| `handoff-confirm` | `/handoff` — Cortex Cloud vs stay on this CLI (Chat · Code · Bot) | [runtime 120x40](runtime/120x40/handoff-confirm.png) | [runtime 40x12](runtime/40x12/handoff-confirm.png) |
| `diagnostics` | Diagnostics tile — error red, warn amber | [120x40](120x40/diagnostics.png) | [40x12](40x12/diagnostics.png) |
| `interrupt-stopped` | Esc / Ctrl+c — `× Stopped` | [120x40](120x40/interrupt-stopped.png) | [40x12](40x12/interrupt-stopped.png) |
| `error-unavailable` | API down — product-facing error | [120x40](120x40/error-unavailable.png) | — |
Expand Down Expand Up @@ -120,6 +126,4 @@ Regenerate: `python3 tools/render_lock_v2.py --index` (fetches IBM Plex Mono on
| `composer-file-chip` | Composer with attached @file chip in prompt | [120x40](120x40/composer-file-chip.png) | [40x12](40x12/composer-file-chip.png) |
| `undo-sheet` | /undo /redo /rewind sheet | [120x40](120x40/undo-sheet.png) | [40x12](40x12/undo-sheet.png) |

**89** boards at 120x40 · **43** at 40x12 · 132 PNGs.

Runtime MockTerminal pack (same ids): [`runtime/120x40`](runtime/120x40/) (89) · [`runtime/40x12`](runtime/40x12/) (43).
**95** runtime boards at 120x40 · **49** at 40x12. Designer PNG pack from other PRs is unchanged; new COR-18/225/227/228 scenes are runtime captures. Computer lock boards from #69 stay in the pack.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions docs/media/tui-lock-v2/runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ is banner green `#1F4945`; historical violet `#A78BFA` is not the lock.
Designer boards (pixel target) live in `docs/media/tui-lock-v2/{40x12,120x40}/`.
These runtime frames are what Designer cli signs off against.

SPEC §7: **89** boards at 120×40 and **43** at 40×12. Each filename is one
SPEC §7: **95** boards at 120×40 and **49** at 40×12. Each filename is one
distinct live state — no two PNGs share a sha256. Includes `/goal` composer
chips (`goal-chip-*`), distinct `offline` and `rate-limit` diagnostics,
Computer lock boards (`computer-disconnected`, `computer-cloud-default`),
local-tools consent, composer `@file` chip, and `/undo` `/redo` `/rewind` sheet.
local-tools consent, composer `@file` chip, `/undo` `/redo` `/rewind` sheet,
and runtime-only COR-18/225/227/228 scenes (`theme-picker`, `handoff-confirm`,
`session-fork`, `init-agents`, `custom-commands`, `hooks-lifecycle`).
60 changes: 60 additions & 0 deletions docs/media/tui-lock-v2/tools/boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,64 @@ def board_slash_model_typed(s, c):
footer(s, c, FOOTER_TYPED_NARROW if c.narrow else FOOTER_TYPED)


def board_init_agents(s, c):
header(s, c)
top = composer(s, c, focused=False, caret=False)
f = Flow(s, c, y=1 if c.narrow else 2, limit=top if c.narrow else top - 1)
if not c.narrow:
f.user("/init", "09:12 AM")
f.reply(
[
"Set up AGENTS.md from the built-in project template. Review the diff, then write it to the repo."
],
"09:12 AM",
)
f.tile("Edit", "AGENTS.md", meta_parts=[("+12", S_OK)])
if c.narrow:
f.line([("+ # Cortex CLI", S_OK)], indent=2)
f.line([("+ Chat | Code | Bot", S_OK)], indent=2)
f.options(["Write AGENTS.md built-in template", "Cancel leave the file untouched"], focused=0)
else:
f.line([("+ # Cortex CLI / Cortex Code", S_OK)], indent=2)
f.line([("+ Chat | Code | Bot in this repository.", S_OK)], indent=2)
f.options(["Write AGENTS.md to the repo", "Cancel"], focused=0)
footer(
s,
c,
[("Enter", "confirm"), ("Esc", "cancel")] if c.narrow else [("↑↓", "select"), ("Enter", "confirm"), ("Esc", "cancel")],
)


def board_hooks_lifecycle(s, c):
header(s, c)
top = composer(s, c, content=[("/hooks", S_ACC), (" ", S)])
if c.narrow:
rows = [
([("pre_tool_use", S)], "before a local tool"),
([("post_tool_use", S)], "after a local tool"),
([("stop", S)], "when the turn stops"),
([("session_start", S)], "plugin event"),
([("session_end", S)], "never consent"),
]
else:
rows = [
([("pre_tool_use", S)], "before a local tool"),
([("post_tool_use", S)], "after a local tool"),
([("stop", S)], "when the turn stops"),
([("session_start", S)], "plugin · terminal notification"),
([("session_end", S)], "lifecycle event — never consent"),
]
menu_top = menu(s, c, top, rows, focused=0, name_w=16)
banner = (
"A hook is never consent. Output is capped and redacted."
if c.narrow
else "`.cortex/hooks.json` — a hook is never consent. Output is capped and redacted."
)
s.put(c.x0 + 2, max(1, menu_top - 2), clip(banner, c.inner_w - 2), S_DIM)
backdrop_tail(s, c, menu_top - 2)
footer(s, c, [("Enter", "select"), ("Esc", "close")] if c.narrow else [("↑↓", "select"), ("Enter", "select"), ("Esc", "close")])


def model_rows():
rows = []
for name, desc, meta in MODELS:
Expand Down Expand Up @@ -1976,6 +2034,8 @@ def board_undo_sheet(s, c):
("goal-chip-budget", board_goal_chip_budget, True, "C", "Composer goal chip — `Goal · budget` (budget_limited), text-only"),
("goal-chip-blocked", board_goal_chip_blocked, True, "C", "Composer goal chip — `Goal · blocked`, text-only"),
("slash-model-typed", board_slash_model_typed, True, "C", "`/mod` typed — banner green matched chars, ghost completion"),
("init-agents", board_init_agents, True, "C", "`/init` — AGENTS.md from the built-in project template"),
("hooks-lifecycle", board_hooks_lifecycle, True, "C", "`/hooks` — pre_tool_use / post_tool_use / stop / session_end"),
("model-list", board_model_list, True, "C", "`/model` — Cortex Mini 1 · Cortex 1 · Cortex Max 1"),
("model-list-hover", board_model_list_hover, False, "C", "Model list with mouse over row 3"),
("model-effort-high", board_model_effort_high, True, "C", "Effort radios — High focused"),
Expand Down
40 changes: 40 additions & 0 deletions docs/media/tui-lock-v2/txt/120x40/hooks-lifecycle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
14K / 500K

> hey 12:49 AM

♦ Thought for 0.4s

Hey — what do you want to work on? 12:49 AM

Worked for 1.8s

> tell me about yourself 12:49 AM

♦ Thought for 0.4s

I'm Cortex, a coding agent that runs in your terminal. 12:49 AM

I mostly help you build and debug software: code, architecture, debugging, reviews, docs, and a bit of research.
Here I run in an interactive terminal, so I can read your files, run commands, and change the project.

In practice:
• I get straight to the point
• I prefer concrete work over long explanations
• I can also discuss, explain, or help you plan

Tell me what you'd like to do.

Worked for 4.6s

`.cortex/hooks.json` — a hook is never consent. Output is capped and redacted.

> pre_tool_use before a local tool
post_tool_use after a local tool
stop when the turn stops
session_start plugin · terminal notification
session_end lifecycle event — never consent
╭─ Agent ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > /hooks │
╰─────────────────────────────────────────────────────────────────────────────────────────── Cortex Mini 1 (medium) ─╯

↑↓:select | Enter:select | Esc:close
40 changes: 40 additions & 0 deletions docs/media/tui-lock-v2/txt/120x40/init-agents.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
14K / 500K

> /init 09:12 AM

Set up AGENTS.md from the built-in project template. Review the diff, then write it to the repo. 09:12 AM

● Edit AGENTS.md · +12
+ # Cortex CLI / Cortex Code
+ Chat | Code | Bot in this repository.
> 1 Write AGENTS.md to the repo
2 Cancel
























╭─ Agent ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > Plan, search, build anything │
╰─────────────────────────────────────────────────────────────────────────────────────────── Cortex Mini 1 (medium) ─╯

↑↓:select | Enter:confirm | Esc:cancel
12 changes: 12 additions & 0 deletions docs/media/tui-lock-v2/txt/40x12/hooks-lifecycle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
14K / 500K
A hook is never consent. Output is …
> pre_tool_use before a local t…
post_tool_use after a local to…
stop when the turn st…
session_start plugin event
session_end never consent
╭─ Agent ────────────────────────────╮
│ > /hooks │
╰─────────── Cortex Mini 1 (medium) ─╯

Enter:select | Esc:close
12 changes: 12 additions & 0 deletions docs/media/tui-lock-v2/txt/40x12/init-agents.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
14K / 500K
● Edit AGENTS.md · +12
+ # Cortex CLI
+ Chat | Code | Bot
> 1 Write AGENTS.md built-in tem…
2 Cancel leave the file untouc…

╭─ Agent ────────────────────────────╮
│ > Plan, search, build anything │
╰─────────── Cortex Mini 1 (medium) ─╯

Enter:confirm | Esc:cancel
10 changes: 6 additions & 4 deletions scripts/render-tui-lock-v2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ for spec in 40x12 120x40; do
python3 scripts/ansi-frames-to-gif.py --frames "$frames" --png-only "$pngs"
done

unique_pngs "$output_dir/40x12" 43
unique_pngs "$output_dir/120x40" 89
unique_pngs "$output_dir/40x12" 49
unique_pngs "$output_dir/120x40" 95

python3 - "$output_dir" <<'PY'
from pathlib import Path
Expand Down Expand Up @@ -100,11 +100,13 @@ is banner green `#1F4945`; historical violet `#A78BFA` is not the lock.
Designer boards (pixel target) live in `docs/media/tui-lock-v2/{40x12,120x40}/`.
These runtime frames are what Designer cli signs off against.

SPEC §7: **89** boards at 120×40 and **43** at 40×12. Each filename is one
SPEC §7: **95** boards at 120×40 and **49** at 40×12. Each filename is one
distinct live state — no two PNGs share a sha256. Includes `/goal` composer
chips (`goal-chip-*`), distinct `offline` and `rate-limit` diagnostics,
Computer lock boards (`computer-disconnected`, `computer-cloud-default`),
local-tools consent, composer `@file` chip, and `/undo` `/redo` `/rewind` sheet.
local-tools consent, composer `@file` chip, `/undo` `/redo` `/rewind` sheet,
and runtime-only COR-18/225/227/228 scenes.

EOF

echo "Wrote runtime captures to $output_dir"
2 changes: 2 additions & 0 deletions src/cortex-tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ rodio = { workspace = true, optional = true }
libc = { workspace = true }

[dev-dependencies]
serial_test = { workspace = true }
tempfile = { workspace = true }
wiremock = { workspace = true }

[lints]
workspace = true
Expand Down
4 changes: 4 additions & 0 deletions src/cortex-tui/src/bin/generate_tui_lock_screenshots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ fn main() {
write_lock_v2_frames(width, height, &output)
}
} else {
if only_flag {
eprintln!("--only requires --v2");
process::exit(1);
}
write_lock_frames(width, height, &output)
};
match result {
Expand Down
1 change: 1 addition & 0 deletions src/cortex-tui/src/commands/executor/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl CommandExecutor {
CommandResult::Async("sessions:list".to_string())
}
"fork" | "branch" => self.cmd_fork(cmd),
"handoff" => self.cmd_handoff(),
"rename" | "mv" => self.cmd_rename(cmd),
"favorite" | "fav" | "star" => CommandResult::Toggle("favorite".to_string()),
"unfavorite" | "unfav" | "unstar" => {
Expand Down
4 changes: 4 additions & 0 deletions src/cortex-tui/src/commands/executor/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ impl CommandExecutor {
CommandResult::OpenModal(ModalType::Fork)
}

pub(super) fn cmd_handoff(&self) -> CommandResult {
CommandResult::Async("handoff".to_string())
}
Comment thread
cursor[bot] marked this conversation as resolved.

pub(super) fn cmd_rename(&self, cmd: &ParsedCommand) -> CommandResult {
match cmd.first_arg() {
Some(name) => CommandResult::SetValue("session_name".to_string(), name.to_string()),
Expand Down
10 changes: 10 additions & 0 deletions src/cortex-tui/src/commands/executor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,16 @@ fn test_agents_command() {
));
}

#[test]
fn test_handoff_command() {
let executor = CommandExecutor::new();
let result = executor.execute_str("/handoff");
assert!(matches!(
result,
CommandResult::Async(ref s) if s == "handoff"
));
}

#[test]
fn test_share_command() {
let executor = CommandExecutor::new();
Expand Down
Loading
Loading