Skip to content

feat: agent-friendly CLI for full okena control + remote window model#138

Open
matej21 wants to merge 5 commits into
mainfrom
feat/agent-cli-window-control
Open

feat: agent-friendly CLI for full okena control + remote window model#138
matej21 wants to merge 5 commits into
mainfrom
feat/agent-cli-window-control

Conversation

@matej21

@matej21 matej21 commented Jun 13, 2026

Copy link
Copy Markdown
Member

Gives the okena CLI (and the remote API it rides on) enough surface for an agent to drive the whole workspace and stay cooperative with what the user sees — create projects/worktrees, manage layout (tabs/splits), run commands, send input, read output, and see the user's windows/projects/terminals.

The remote action API was already nearly complete, so most of this is CLI surface — plus one real API addition: a window model (the remote previously saw only a flat workspace).

What's new

Window model in the remote API

  • GET /v1/state now returns windows (ApiWindow[]): each open OS window with its active flag, per-window focus (project + terminal), fullscreen target, visible projects (via the same visible_projects() the sidebar uses), folder filter, OS bounds, and sidebar state. Built by Okena::build_api_windows.
  • Back-compat: windows is #[serde(default)]; the flat focused_project_id/fullscreen_terminal are derived from the active window, so existing mobile/web clients keep working.

Per-window action targeting (--window)

  • FocusTerminal, SetProjectShowInOverview, SetFullscreen gained an optional window field ("main" | extra UUID). The bridge parses it and the generalized FocusManagerResolver (Fn(&App, Option<WindowId>) -> Option<…>) routes the mutation to that window's FocusManager; None keeps today's focused-window default.
  • AddProject now also returns the new project_id (was terminal ids only).

Agent-friendly CLI on clap

  • Orientation: ls (windows + projects/layout tree, --json), term ls.
  • Projects: project add|rm|show|hide|rename|color|focus.
  • Worktrees: worktree add|rm. Folders: folder add|rm|rename.
  • Terminals/layout: term new|close|focus|rename|split|tab|minimize|fullscreen — split/tab resolve the layout path from a terminal id client-side, so agents never compute tree paths.
  • I/O loop: send, run, key, read.
  • Global --window (main / full id / unique prefix) for the per-window commands.
  • Addressing: projects by name/id/path; terminals by id, project/name, or project:index. All resolvers are pure + unit-tested.
  • Existing verbs (pair/health/state/action/services/service/whoami) preserved. The CLI gate only engages on a known subcommand, so GUI launch and --profile flags are untouched.

Commits (phased)

  1. feat(api) — window-model + targeting DTOs
  2. feat(remote) — backend: build_api_windows, --window routing, AddProject project_id, headless variants
  3. feat(cli) — clap command tree + resolvers
  4. test — StateResponse test-helper fixups
  5. docs — window model + src/cli/CLAUDE.md

Testing

  • cargo build -p okena clean; cargo test: okena-core 80, okena-workspace 287, okena 110 — all green.
  • Smoke-tested live: okena ls against a running instance auto-registers and renders the real workspace.

Note

Against an older running instance the windows list is empty (no crash — serde default), so the ls WINDOWS section and --window only light up after rebuilding + restarting okena.

🤖 Generated with Claude Code

matej21 and others added 5 commits June 13, 2026 12:54
Expose multi-window state over the remote API so CLI/remote clients can
see what the user actually sees:

- ApiWindow / ApiWindowBounds DTOs and StateResponse.windows (serde
  default → backward compatible with old clients).
- Optional `window` targeting field on FocusTerminal,
  SetProjectShowInOverview, and SetFullscreen, plus
  ActionRequest::target_window() to read it.

Types only; backend wiring and CLI land in follow-up commits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read side: GET /v1/state now returns `windows` — each open OS window with
its active flag, per-window focus (project + terminal), fullscreen target,
visible projects (via the same visible_projects() the sidebar uses),
folder filter, OS bounds, and sidebar state. Back-compat flat
focused_project_id/fullscreen_terminal are derived from the active window.

Write side: actions carrying `window: "main"|<uuid>` now land on that
window's per-window FocusManager. FocusManagerResolver gained an
Option<WindowId> target arg (None = focused/active window, as before);
the bridge parses ActionRequest::target_window(), rejects malformed ids,
and reports "window not found" for a missing extra. New
Okena::focus_manager_for_window + build_api_windows; headless provides
single-main-window equivalents.

Also: AddProject now returns the new project_id alongside terminal_ids.

Threads the new SetFullscreen/FocusTerminal/SetProjectShowInOverview
`window` field through strip_remote_ids and GUI-internal constructions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hand-rolled arg parser with a clap (derive) command tree and
add full control over a running okena instance over the remote API:

- Orientation: `ls` (windows + projects/layout tree, --json), `term ls`.
- Projects: `project add/rm/show/hide/rename/color/focus`.
- Worktrees: `worktree add/rm`.  Folders: `folder add/rm/rename`.
- Terminals/layout: `term new/close/focus/rename/split/tab/minimize/
  fullscreen` — split/tab resolve the layout path from a terminal id.
- I/O loop: `send`, `run`, `key`, `read`.
- Global `--window` targets a specific window (main / id / unique prefix)
  for the per-window commands.

Agent-friendly addressing: projects by name/id/path; terminals by id,
`project/name`, or `project:index`; windows by id prefix. All resolvers
are pure and unit-tested. Existing verbs (pair/health/state/action/
services/service/whoami) preserved. The CLI gate only engages on a known
subcommand, so GUI/profile launch is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new StateResponse.windows field (a serde-default Vec) is omitted by
two #[cfg(test)] construction sites that the non-test build never
compiles. Initialize them to empty so `cargo test` builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Note the state `windows` list and per-window action targeting in the
remote server CLAUDE.md, and add src/cli/CLAUDE.md covering the clap gate,
addressing scheme, and command conventions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant