Skip to content

Latest commit

 

History

History
1271 lines (964 loc) · 43.2 KB

File metadata and controls

1271 lines (964 loc) · 43.2 KB

CoCalc CLI Interface Plan

See also: Dev CLI Wishlist

TODO:

  • ideas to expand the browser api:
    • make process info available (i.e., categorized list of processes spawned by the project shown in processes)
    • make the project log available, so agent knows recent/all activity by users
  • make sure to delete the whole "CURRENTLY NOT USED" thing in db-schema/projects.ts
  • browser automation policy hardening: see browser-automation-policy.md
  • implement "host stop".
  • Projects: name versus title. Right now we're using the project title (which can have any characters in it and is easy to change at any time) for naming things, which isn't great. There's also a "name" field associated to a project, which is much more constrained. We should accept that for "-w" and also change the whole UI to strongly suggest choosing a name when making a project.
  • When making a project or host, show the corresponding cocalc cli command, like GCP does. See http://localhost:7000/projects/00000000-1000-4000-8000-000000000000/files/home/wstein/build/cocalc-lite4/lite4.chat#chat=1771453636305
  • We really need some good documentation for all this... in a form that is extremely AI Agent friendly(!). E.g., it's so important to point out that this is genuine full ssh, and fully supports port forwarding, X11 forwarding. It's not just a half-broken "ssh gateway", but the real deal.
  • client and server versioning...
  • rewrite all the code in the cli to benefit from typescript for the cocalc api -- http://localhost:7000/projects/00000000-1000-4000-8000-000000000000/files/home/wstein/build/cocalc-lite4/lite4.chat#chat=1771572607303
  • cloudflare ssh integration.
  • get logs from host (i.e., /mnt/cocalc/data/log), similar to how that works with kubernetes
  • upgrade host (or set host to a specific version)
  • ssh to host (or something like "kubectl exec bash").

Current Status Snapshot

Browser CLI + Exec Runtime

Area Status Notes
browser session list/use/clear done Browser heartbeat + active session targeting is in place.
browser open/close (multiple files) done Multi-file open/close in one command.
browser exec done Inline JS, --file, --stdin, configurable timeout.
browser exec LRO done start/get/wait/cancel implemented and exposed in CLI.
browser exec-api done Prints TypeScript API declaration + usage snippets.
api.notify done In-browser notifications (show/info/success/warning/error).
api.fs done Node-like async fs + find/fd/ripgrep/dust wrappers.
api.bash done Blocking + async job lifecycle (run/start/get/wait).
api.notebook MVP listCells, runCells, setCells.
api.terminal MVP list/openSplit/spawn/write/history/state/cwd/resize/destroy.
api.timetravel MVP+ patchflow/snapshots/backups/git list/get primitives.
syncdoc handling done Direct syncdoc open path + refcounted reuse + cleanup.
lite-mode browser support done Browser CLI flow works with lite hub surface.
extension runtime MVP Session-scoped api.extensions with hello-world editor demo.

Current High-Priority Next Steps

  • Harden lite-mode conat auth defaults and agent-scope token model.
  • Expand notebook editing API beyond set/run/list.
  • Add richer timetravel helpers (restore/search/summarize) at unified layer.
  • Extend extension runtime from hello-world MVP to generic bundle/manifest install.
  • Add policy/approval hooks directly in browser exec API methods.

Live Browser Automation Feedback

This is direct feedback from a real debugging session against the lite dev env while reproducing Jupyter keyboard-routing issues with floating agent windows.

What worked well

  • browser action click
  • browser action type
  • browser screenshot
  • browser logs tail
  • raw browser exec for DOM and runtime inspection

Friction Found

Session targeting is too easy to get wrong

  • after a reload, a second active browser session appeared for the same live browser tab
  • unpinned commands then targeted the newer session implicitly
  • this is dangerous for debugging because the agent can think it is operating on the user's exact tab when it is not

Requested improvement:

  • once a browser session is selected, strongly prefer strict target pinning by default
  • make any fallback to a different browser id very explicit

Target context output can be inconsistent

  • one command reported a target_session_url of project home while the actual runtime page_url and DOM state were on the notebook tab
  • this makes it harder to trust CLI output during debugging

Requested improvement:

  • ensure target_browser_id, target_session_url, and runtime page_url always agree, or emit a clear mismatch warning

click-at is literal topmost-hit behavior

  • trying to click the notebook underneath an overlapping floating dock hit a dock button instead
  • this made it awkward to force the notebook into command mode when debugging keyboard ownership under overlays

Requested improvement:

  • add better selector-driven focus/click helpers
  • consider higher-level notebook/editor actions for "focus selected cell", "enter command mode", etc.

press and type differ significantly on contenteditable surfaces

  • browser action type appended text correctly in the floating agent editor
  • browser action press on the same contenteditable selector did not insert text, even though it did preserve focus and was useful for shortcut leakage checks

Requested improvement:

  • document this distinction more clearly
  • add richer diagnostics for press, including before/after active element and whether keydown and input reached the intended target

Menus still require raw DOM scripting

  • opening the ... menu worked fine
  • selecting a menu item by label still required raw DOM inspection to find the generated selector

Requested improvement:

  • add actions such as click-text, click-menu-item, or select-menu-item

High-level browser API helpers can stall in busy live sessions

  • browser action plus raw DOM inspection was reliable
  • some higher-level helpers like file opening and notebook cell listing were more likely to stall during a busy live-session workflow

Requested improvement:

  • harden those helpers for live sessions
  • add better timeout/error reporting so the caller can distinguish "slow" from "stuck"

Goals

  • Provide a single, scriptable CLI for CoCalc Launchpad and related products.
  • Use user-facing terminology: project instead of workspace.
  • Cover both major control-plane entities:
    • projects
    • hosts
  • Match the practical ergonomics of Sprites CLI (auth, list/create/use, exec/console, proxy URL workflows).
  • Make CoCalc AI-agent-friendly by exposing stable, scriptable primitives for files, search, notebooks, and browser-session automation.
  • Keep implementation SEA-friendly:
    • JS/TS only
    • no native compiled dependencies in the core CLI path
    • single-file bundle for SEA without extraction of native addons

Non-goals (initially)

  • Replacing every internal admin operation on day one.
  • Building a full TUI dashboard.
  • Supporting every edge-case interactive flow before scriptable flows are stable.

Product Naming and Command Identity

  • Binary name: cocalc
  • Primary noun: project
  • Keep internal code references to "project" in adapters only.

Examples:

cocalc project list
cocalc project create my-notebook
cocalc project exec my-notebook -- uname -a

CLI Design Principles

  • API-first, script-first:
    • every command supports stable machine output via --json
    • deterministic exit codes
  • Human mode should remain concise and readable.
  • Strongly typed command adapters so TypeScript catches API drift during build.
  • Resource targeting should be flexible:
    • by id
    • by name
    • by active context (use)
  • Consistent verb structure:
    • list, get, create, update, delete
    • start, stop, restart
    • move, copy, restore

Global UX Contract

All commands support:

  • --json machine-readable output
  • --output table|json|yaml (default table in human mode, using ascii-table3)
  • --quiet
  • --verbose
  • --org <org> or equivalent context selector
  • --profile <name> config profile
  • --api <url> override base API URL
  • --timeout <duration> for blocking operations
  • --wait for asynchronous operations that can be waited on

Tooling Choices

  • Command parser framework: commander (required) to avoid ad hoc argument parsing drift.
  • Human tables: ascii-table3 (required) for compact, stable terminal formatting.
  • Keep command and output wiring centralized so global options (--json, --wait, --timeout) behave identically everywhere.

Exit Code Contract

Proposed standardized exit codes:

  • 0 success
  • 1 usage/validation error
  • 2 auth error
  • 3 permission denied
  • 4 not found
  • 5 conflict/precondition failed
  • 6 timeout
  • 7 network/transport error
  • 8 server/internal error

Config and Context Model

Config file:

  • ~/.config/cocalc/config.json (Linux/macOS)
  • %APPDATA%/cocalc/config.json (Windows)

Context layers:

  1. command flags
  2. env vars
  3. active profile config
  4. defaults

Suggested env vars:

  • COCALC_API_URL
  • COCALC_TOKEN
  • COCALC_PROFILE
  • COCALC_ORG
  • COCALC_OUTPUT

Local directory context files:

  • .cocalc-project (active project id/name for current directory)
  • .cocalc-org (optional org affinity)

Authentication Model

Commands

cocalc auth login [--api <url>] [--org <org>] [--token <token>]
cocalc auth setup --token <token>
cocalc auth status
cocalc auth logout [--all] [--force]
cocalc auth list
cocalc auth use <profile-or-org>

Keyring strategy (SEA-friendly)

Phase strategy:

  1. Default encrypted-at-rest file token storage using Node crypto (no native deps).
  2. Optional keyring integration via subprocess wrappers (not native Node addons):
    • macOS security
    • Linux secret-tool or pass
    • Windows cmdkey/Credential Manager bridge
  3. Explicit command toggles:
cocalc auth keyring enable
cocalc auth keyring disable

This preserves single-file SEA reliability while leaving room for OS-native storage later.

Top-Level Command Surface (Full Plan)

1) Project lifecycle (project)

cocalc project create [name] [--host <host>] [--json]
cocalc project list [--prefix <name>] [--state <state>] [--json]
cocalc project get <project>
cocalc project use <project>
cocalc project unuse
cocalc project rename <project> <new-name>
cocalc project delete <project> [--force]
cocalc project start <project> [--wait]
cocalc project stop <project> [--wait]
cocalc project restart <project> [--wait]

Notes:

  • <project> accepts id or name.
  • use writes local .cocalc-project.

2) Project access and execution

cocalc project exec <project> -- <cmd...>
cocalc project ssh <project> [ssh-args...]
cocalc project console <project>
cocalc project terminal <project>
cocalc project sync up <project> --local <dir> --remote <path> [--watch]
cocalc project sync down <project> --remote <path> --local <dir>
cocalc project sync bidir <project> --local <dir> --remote <path> [--watch]

Notes:

  • project sync is planned to use reflect-sync under the hood for fast SSH-based incremental sync.

3) Project file operations

cocalc project file list <project> [path]
cocalc project file cat <project> <path>
cocalc project file put <project> <src> <dest>
cocalc project file get <project> <path> <local-dest>
cocalc project file rm <project> <path>
cocalc project file rg <project> <pattern> [path] [-- <rg-args...>]
cocalc project file fd <project> [pattern] [path] [-- <fd-args...>]

Notes:

  • Project file operations should work even when the project is stopped, whenever possible, by routing through project-host file services instead of requiring runtime startup.
  • rg/fd support is explicitly included for AI-agent productivity.

4) Project transfer and placement

cocalc project move <project> --host <host> [--wait]
cocalc project copy-path \
  --src-project <project> --src <path> \
  --dest-project <project> --dest <path> [--wait]
cocalc project placement <project>

5) Project snapshots (fast btrfs) and backups (durable rustic)

cocalc project snapshot create <project>
cocalc project snapshot list <project>
cocalc project snapshot info <project> <snapshot>
cocalc project snapshot delete <project> <snapshot>
cocalc project snapshot restore-path <project> --snapshot <id> --path <src> [--dest <dest>] [--wait]
cocalc project snapshot restore-all <project> --snapshot <id> [--wait]

cocalc project backup create <project> [--wait]
cocalc project backup list <project>
cocalc project backup files <project> --backup <id> [path]
cocalc project backup restore-path <project> --backup <id> --path <src> [--dest <dest>] [--wait]
cocalc project backup restore-all <project> --backup <id> [--wait]

Notes:

  • snapshot is the canonical CLI term for CoCalc btrfs snapshots (faster than backup/checkpoint systems that scale with data size).
  • backup is for rustic/off-host durability and is slower.
  • Current backend capability is path restore; restore-all is intentionally included in the interface plan as a target capability to implement.
  • Optional compatibility aliases can be provided later: checkpoint -> snapshot.

6) Project HTTP proxy / app URL workflows

cocalc project proxy url <project> --port <port> [--host <host>] [--open]
cocalc project proxy token issue <project> --host <host> [--ttl <seconds>]
cocalc project proxy curl <project> --port <port> [--host <host>] [--path <path>]

Rationale:

  • This aligns with your smoke-test need to verify denied access without token and allowed access with token.
  • It can compose existing host-connection and token issuance APIs.

7) Host lifecycle and operations

cocalc host list [--all] [--json]
cocalc host get <host>
cocalc host create <name> [--region ...] [--size ...]
cocalc host start <host> [--wait]
cocalc host stop <host> [--wait]
cocalc host restart <host> [--wait]
cocalc host deprovision <host> [--wait] [--force]

cocalc host software upgrade <host> [--target all|project-host|project]
cocalc host connector upgrade <host> [--version <v>]
cocalc host logs <host> [--follow]
cocalc host resolve-connection <host>
cocalc host issue-http-token --host <host> [--project <project>] [--ttl <seconds>]

8) Long-running operations (op)

cocalc op list [--scope project|host] [--id <id>]
cocalc op get <op-id>
cocalc op wait <op-id> [--timeout 5m]
cocalc op cancel <op-id>

9) Utility/admin commands

cocalc doctor
cocalc config get [key]
cocalc config set <key> <value>
cocalc config list
cocalc version

10) Browser session automation (active roadmap)

cocalc browser session list
cocalc browser use <session-id>
cocalc browser files
cocalc browser open <project> <path...>
cocalc browser close <project> <path...>
cocalc browser exec-api
cocalc browser exec <project> [code...]
cocalc browser exec <project> --file <script.js>
cocalc browser exec <project> --stdin
cocalc browser exec --async --wait ...
cocalc browser exec-get <exec-id>
cocalc browser exec-wait <exec-id>
cocalc browser exec-cancel <exec-id>

Notes:

  • This is for agent/human collaboration workflows where a turn is associated with a browser session id.
  • browser exec should run in a constrained frontend API sandbox (e.g., restricted Redux helpers with approval boundaries).
  • The API should be expanded systematically by capability domain so agents can compose reliable automations.

11) Browser exec API expansion plan (agent-first)

Goal:

  • Make browser automation powerful enough that a user can ask for real end-to-end help ("create notebook, run, explain, notify me"), and an agent can do it with deterministic scriptable primitives.

Design rule:

  • Prefer a small number of composable primitives over many one-off commands.
  • Every state-changing primitive should support approval hooks and clear audit events.
  • Return data should be stable, typed, and easy for LLMs to consume.
  • Design for multiple CoCalc products/environments, not Launchpad-only behavior.

11.0 Product mode compatibility (cocalc-plus / lite vs Launchpad)

The browser exec architecture must be mode-aware:

  • launchpad mode:
    • rich host-backed functionality
    • timetravel providers: patchflow, snapshots, backups, git
  • lite mode (cocalc-plus):
    • no host backup/snapshot infrastructure
    • timetravel providers: typically patchflow, optionally git

Agent-facing implication:

  • Never hardcode provider assumptions in scripts.
  • Scripts should discover capabilities first, then branch.

Required primitives:

  • api.system.getCapabilities():
    • { product_mode: "launchpad" | "lite" | "unknown", features: {...} }
  • api.timetravel.listProviders(path):
    • authoritative provider list for a file in the current environment
  • api.exec.getApiVersion():
    • compatibility/version negotiation for script portability

CLI implication:

  • cocalc browser exec-api should include:
    • API version
    • product-mode notes
    • capability discovery snippet

11.1 Core domains and API shape

api.session

  • getInfo() browser/session/project context metadata
  • listOpenProjects()
  • listOpenFiles({ projectId? })
  • focusProject(projectId)
  • focusFile(projectId, path)

api.files

  • list({ path, depth?, hidden? })
  • readText(path, { start?, end? })
  • writeText(path, content, { create?, overwrite? })
  • patchText(path, edits)
  • mkdir(path, { parents? })
  • remove(path, { recursive?, trash? })
  • move(src, dest, { overwrite? })
  • copy(src, dest, { overwrite? })

api.fs (node-compatible filesystem API + safe power tools)

  • Expose the existing async node-style filesystem surface from src/packages/conat/files/fs.ts as directly as possible.
  • This gives agents a familiar API from training data, including binary-safe reads/writes.
  • Key methods:
    • readFile(path, encoding?)
    • writeFile(path, data)
    • readdir(path, opts?)
    • stat(path), lstat(path), exists(path)
    • mkdir, rm, rename, copyFile, cp, move
    • watch, find, fd, ripgrep, dust
  • Important behavior:
    • Works even when project runtime is not running (through file service backend).
    • Supports Buffer payloads for binary workflows.
    • Includes resource-limited, argument-whitelisted command wrappers for safety.
  • Return normalization guidance:
    • Keep raw stdout/stderr buffers available.
    • Provide optional helper decoding for agent ergonomics (utf8, JSON lines parsing).

api.editor

  • open(paths, opts)
  • close(paths)
  • getSelection(path?)
  • setSelection(path, range)
  • reveal(path, { line, column })
  • save(path?)
  • saveAll()

api.notebook

  • listCells(path)
  • getCells(path, { ids?, includeOutputs? })
  • setCells(path, updates)
  • insertCells(path, inserts)
  • deleteCells(path, ids)
  • moveCells(path, moves)
  • runCells(path, ids?)
  • runAll(path)
  • interruptKernel(path)
  • restartKernel(path, { runAll? })
  • getKernelStatus(path)

api.timetravel (unified history API across providers)

  • listProviders(path) -> ["patchflow", "snapshots", "backups", "git"] subset per file
  • listVersions(path, opts) where opts includes:
    • provider?: "patchflow" | "snapshots" | "backups" | "git"
    • from_ms?, to_ms?
    • limit?, order?
    • query? (provider-specific search text / metadata filter)
  • getVersion(path, { provider, version_id })
  • getVersionText(path, { provider, version_id })
  • diffVersions(path, { from, to, provider? })
  • restoreVersion(path, { provider, version_id, dest_path?, mode? })
  • search(path, opts) unified search over one or more providers
  • summarize(path, opts) compact activity summary over a time range

Provider helpers for agent ergonomics:

  • api.timetravel.patchflow.*
  • api.timetravel.snapshots.*
  • api.timetravel.backups.*
  • api.timetravel.git.*

Notes:

  • Keep one top-level api.timetravel namespace for composability.
  • Expose provider-specific helpers underneath it, rather than four disconnected top-level APIs.
  • This matches how users think ("history of this file"), while still allowing explicit source control.

api.bash (project command execution with async/streaming control)

  • Expose a focused bash execution API in browser exec for composability inside larger scripts.
  • Back it directly by the existing execute-code contract in src/packages/util/types/execute-code.ts.
  • Core methods:
    • run(opts) blocking execution (returns stdout/stderr/exit_code)
    • start(opts) async execution (returns job metadata quickly)
    • get(jobId, opts?) poll job status/output
    • await(jobId, opts?) wait until completion
    • kill(jobId) terminate running job
    • stream(jobId, onEvent) optional realtime events (stdout, stderr, stats, done, error)
  • Key options (aligned with existing execute-code options):
    • command, args?, bash?, cwd?, path?
    • env?, timeout?, max_output?
    • err_on_exit?, ulimit_timeout?, filesystem?
  • Why this belongs in browser exec API:
    • agents can call bash in the middle of a larger browser-side workflow without extra RPC round trips
    • enables one-shot workflows like search -> transform -> open -> notify in a single script
    • leverages tooling agents are extremely strong at

api.terminal (high-value, carefully gated)

  • listSessions()
  • openSession(opts)
  • exec(command, opts) non-interactive convenience
  • write(sessionId, input)
  • read(sessionId, { maxBytes? })
  • interrupt(sessionId)
  • close(sessionId)

api.chatroom

  • listThreads(path)
  • createThread(path, opts)
  • pinThread(path, threadId)
  • listMessages(path, opts)
  • postMessage(path, opts)
  • deleteMessages(path, opts) destructive + approval

api.ui

  • notify.show/info/success/warning/error(...) (already started)
  • confirm(prompt, opts) explicit user prompt/approval
  • modal(opts) rich interaction surface
  • status(text) transient progress indicator
  • copyToClipboard(text)

api.search

  • rg(pattern, opts) scoped ripgrep abstraction
  • findFiles(glob, opts)
  • findSymbols(query, opts) where available

api.project

  • start(projectId?)
  • stop(projectId?)
  • restart(projectId?)
  • setTitle(projectId, title)
  • openInNewTab(projectId, path?)

11.2 What users ask vs required primitives

"Summarize files I have open"

  • Needs api.session.listOpenFiles + api.files.readText.

"Open notebooks mentioning elliptic curves, newest first"

  • Needs api.fs.ripgrep + api.fs.stat + api.editor.open.

"Open matching notebooks and run all cells so they are ready"

  • Needs api.fs.ripgrep + api.editor.open + api.notebook.runAll.

"Convert notebooks to .py and combine into a library"

  • Needs api.fs.find/fd + notebook conversion helpers + api.fs.writeFile.

"Run project-level transformations in the middle of a browser script"

  • Needs api.bash.run/start/get/await + api.fs + api.editor/api.notebook.

"Create a notebook to analyze X and run all cells"

  • Needs api.notebook.insert/set/runAll + api.ui.notify.

"Close all markdown files"

  • Needs api.session.listOpenFiles + api.editor.close.

"Fix this project and show me what changed"

  • Needs api.search, api.files, api.terminal.exec (or backend tools), api.ui.modal/notify.

"Notify me when done"

  • Needs api.ui.notify + long-running exec lifecycle.

"Restore the file a.tex from the last backup"

  • Needs api.timetravel.listVersions({ provider: "backups" }) + api.timetravel.restoreVersion.

"Search snapshots of a.ipynb for the last version that ran without errors and copy it to a-working.ipynb"

  • Needs api.timetravel.listVersions({ provider: "snapshots" }) + api.timetravel.getVersion + api.notebook.listCells/output checks + api.timetravel.restoreVersion({ dest_path }).

"Summarize activity on a.txt over the last two days"

  • Needs api.timetravel.search + api.timetravel.summarize.

11.3 Approval and safety model

Policy levels:

  • read: metadata + text reads
  • write: file/editor/notebook edits
  • exec: terminal command execution
  • bash_exec: project bash command execution
  • destructive: deletes/resets/kernel restarts
  • ui_prompt: user-facing modal/confirm interactions

Mutation safety policy (snapshot-first by default):

  • Default in Launchpad: snapshot_before_mutation for any write, bash_exec, or destructive action.
  • Optional stricter policy: snapshot_before_turn (one snapshot at turn start) plus per-mutation checkpoints for high-risk flows.
  • Optional recovery policy: snapshot_and_auto_rollback_on_failure for scripted workflows.
  • Opt-out policy for advanced users: no_auto_snapshot with explicit warning.
  • For lite mode (no host snapshot provider), degrade gracefully:
    • required snapshot policy blocks mutation with a clear error.
    • preferred snapshot policy warns and continues.

Policy hooks:

  • api.safety.beginTurn({ snapshot: "if_available" | "required" | "none" })
  • api.safety.beforeMutation({ reason, paths? })
  • api.safety.endTurn({ summarize_changes?: boolean })

Execution flow:

  • Preflight permission plan from script (or dynamic prompts).
  • Per-call approval where policy requires it.
  • Every mutating call logged with timestamp, actor, project, args summary.
  • Support dry-run for destructive families when feasible.

11.3.1 Browser action surface expansion (implemented)

The typed browser action API now includes:

  • navigate
    • fields: url, replace?, wait_for_url_ms?
  • scroll_by
    • fields: dx?, dy?, behavior?
  • scroll_to
    • selector mode: selector, block?, inline?, timeout_ms?, poll_ms?
    • absolute mode: top?, left?, behavior?
  • batch
    • fields: actions: BrowserAtomicActionRequest[], continue_on_error?
    • executes multiple typed steps in one RPC call to reduce latency/races

CLI coverage:

  • cocalc browser action navigate <url> ...
  • cocalc browser action scroll-by <dy> [dx] ...
  • cocalc browser action scroll-to [--selector ... | --top ... --left ...] ...
  • cocalc browser action batch --file <actions.json> ...

Batch file format:

{
  "continue_on_error": false,
  "actions": [
    { "name": "navigate", "url": "http://localhost:7003/..." },
    { "name": "scroll_to", "selector": ".cell", "block": "center" },
    { "name": "wait_for_selector", "selector": ".plot-container", "state": "visible" },
    { "name": "click", "selector": ".run-button" }
  ]
}

Current practical guidance for notebook/virtualized UIs:

  • Prefer scroll_to before interaction when DOM virtualization is present.
  • For iframe-heavy outputs (e.g., plotly inside iframe), top-document coordinate actions can miss inner targets; this is a known limitation and motivates frame-aware routing.

11.4 Data contracts and ergonomics

  • Paths are absolute everywhere.
  • IDs are stable (project_id, cell.id, thread.id, etc.).
  • Internal compatibility note: browser API can map project_id to backend project_id in adapters.
  • Optional output simplification knobs:
    • notebook outputs: raw|summary|text
    • terminal output: bounded windows
  • Return objects should include:
    • ok
    • changed counts
    • warnings
    • deterministic identifiers

11.5 Operational model for agents

  • Keep current async LRO-style exec (start/get/wait/cancel) as the primary control plane.
  • Add optional event streaming later (exec-stream) for progress and approvals.
  • Add script source options (inline/file/stdin) for robust agent invocation.
  • Keep exec-api as canonical discoverability endpoint (TS declaration output).

11.6 Phased implementation

Phase A (near-term)

  • Make cocalc browser ... work in lite mode by wiring against src/packages/lite/hub (parallel lightweight API surface to server conat API), so browser automation can be used during ongoing development.
  • Expand api.session, api.files (read/write text), api.editor save/focus. (in progress)
  • Expose api.fs node-compatible baseline (readFile/writeFile/readdir/stat/rm/mkdir/rename) plus safe ripgrep/find/fd.
  • Harden api.notebook with insert/delete/move + kernel status. (in progress)
  • Add api.ui.confirm and richer notify variants. (in progress)
  • Add api.timetravel MVP (listProviders, listVersions, getVersionText, restoreVersion) with patchflow + snapshots first. (in progress)

Phase B

  • Add api.chatroom primitives.
  • Add api.search primitives.
  • Add better notebook output modes and size controls.
  • Extend api.timetravel with backups + git providers and unified search/summarize.

Phase C

  • Add api.terminal safe subset with approval gating.
  • Add api.bash with async job lifecycle + optional stream events.
  • Add event stream support for long interactive automations.

Phase D

  • Advanced UI automation:
    • modal forms
    • guided workflows
    • richer progress/status surfaces.

11.7 Concrete extension API spec (proposed)

Purpose:

  • Let agents deliver repeatable, user-scoped frontend functionality by shipping extension bundles, not one-off ad hoc scripts.
  • Reuse CoCalc's runtime editor registration model in a controlled, capability-gated way.

High-level model:

  • Agent builds extension bundle (single JS file + manifest).
  • Agent installs extension via browser API (api.extensions.install).
  • Extension activates in current browser session and can register editors/panels/actions.
  • User can open extension-backed files (e.g., browser.gitview) or panels.

TypeScript-style manifest:

export type ExtensionCapability =
  | "read_files"
  | "write_files"
  | "read_timetravel"
  | "restore_timetravel"
  | "read_git"
  | "exec_terminal"
  | "bash_exec"
  | "ui_notify"
  | "ui_modal"
  | "network_fetch";

export type ExtensionManifest = {
  id: string;                  // e.g. "com.cocalc.gitview"
  name: string;
  version: string;             // semver
  description?: string;
  entry: string;               // entry module symbol/path in bundle
  capabilities: ExtensionCapability[];
  compatibility?: {
    api_min?: string;
    api_max?: string;
    product_modes?: ("launchpad" | "lite")[];
  };
};

Browser API surface:

api.extensions = {
  list(): Promise<ExtensionSummary[]>;
  get(id: string): Promise<ExtensionDetails>;
  install(opts: {
    manifest: ExtensionManifest;
    bundle_js: string;
    replace?: boolean;
    scope?: "session" | "user" | "project";
  }): Promise<{ ok: true; id: string; version: string }>;
  enable(id: string): Promise<{ ok: true }>;
  disable(id: string): Promise<{ ok: true }>;
  uninstall(id: string): Promise<{ ok: true }>;
  invoke(id: string, command: string, args?: unknown): Promise<unknown>;
};

Extension runtime context:

export type ExtensionContext = {
  extension: { id: string; version: string };
  api: {
    session: ...;
    files: ...;
    notebook: ...;
    timetravel: ...;
    ui: ...;
  };
  registerEditor(spec: {
    id: string;
    name: string;
    file_extensions: string[];              // e.g. [".gitview"]
    can_open?: (path: string) => boolean;
    open: (path: string, opts?: unknown) => Promise<EditorHandle>;
  }): () => void;
  registerPanel(spec: {
    id: string;
    name: string;
    open: (opts?: unknown) => Promise<PanelHandle>;
  }): () => void;
  registerAction(spec: {
    id: string;
    label: string;
    run: (args?: unknown) => Promise<unknown>;
  }): () => void;
  onDispose(fn: () => void): void;
};

export async function activate(ctx: ExtensionContext): Promise<void>;
export async function deactivate?(): Promise<void>;

Editor registration behavior:

  • Extension editors are user-scoped and hot-loadable.
  • Registration is reversible (returns disposer).
  • Opening a matching file extension dispatches to extension editor implementation.
  • Extensions must render via approved UI host primitives (no unrestricted DOM ownership).

Capability + approval policy:

  • Install requires explicit approval when capabilities include write_files, exec_terminal, bash_exec, network_fetch, or destructive history restore.
  • Runtime calls are capability-checked per API method.
  • All extension-originated mutating actions are audit logged with extension id + version.

Persistence and sharing:

  • Scope options:
    • session: current browser session only
    • user: persists for user account
    • project: stored in project config (shareable with collaborators)
  • Initial implementation can support session first, then user, then project.

Suggested CLI surface:

cocalc browser ext list
cocalc browser ext install --manifest ./ext.json --bundle ./ext.js [--scope session|user|project]
cocalc browser ext enable <id>
cocalc browser ext disable <id>
cocalc browser ext uninstall <id>
cocalc browser ext invoke <id> <command> [--arg-json ...]

Target example:

  • com.cocalc.gitview extension registers .gitview editor.
  • Opening browser.gitview shows recent commits/diffs for current repo.
  • Agent iterates quickly by replacing bundle version via install --replace.

Mode compatibility guidance:

  • Extensions should branch on api.system.getCapabilities() + api.timetravel.listProviders(path).
  • In lite mode, hide snapshot/backup UI paths automatically when those providers are unavailable.

Success metrics:

  • Median user request can be resolved with <=2 browser exec calls.
  • 90% of common notebook/file/chat tasks handled without bespoke backend changes.

  • Low timeout/cancellation failure rates on async exec operations.

12) Notebook operations (future standalone commands)

cocalc project jupyter --path <ipynb> run <cell-id...>
cocalc project jupyter --path <ipynb> add --after <cell-id> [--type code|markdown] [--source <text>]
cocalc project jupyter --path <ipynb> delete <cell-id...>
cocalc project jupyter --path <ipynb> move <cell-id> --before <cell-id>
cocalc project jupyter --path <ipynb> list-cells

Notes:

  • Cell-id-addressable operations are preferred for deterministic agent workflows.
  • Follow-up can add execution result streaming and kernel state inspection.

13) Chatroom operations (future standalone commands)

cocalc project chatroom --path <chat-path> thread list
cocalc project chatroom --path <chat-path> thread create --title <title> [--type codex|general]
cocalc project chatroom --path <chat-path> thread pin <thread-title-or-id>
cocalc project chatroom --path <chat-path> thread unpin <thread-title-or-id>

cocalc project chatroom --path <chat-path> message list [--thread <thread>] [--limit <n>]
cocalc project chatroom --path <chat-path> message delete --older-than 7d [--thread <thread>] [--yes]

Notes:

  • The command surface should support common automation flows such as:
    • pinning a thread (e.g., "Todo list")
    • creating a new Codex thread
    • deleting messages older than a retention threshold
  • Destructive operations (e.g., message deletion) should require explicit confirmation flags (--yes) and support dry-run previews where possible.
  • Chatroom APIs should be exposed in a way that supports both human workflows and agent automation.

14) Product launcher subcommands (future)

cocalc plus [args...]
cocalc launchpad [args...]

Behavior:

  • If cocalc-plus / cocalc-launchpad is not installed, prompt and install it via the corresponding installer.
  • Then forward all remaining arguments to the installed binary.
  • Provide non-interactive flags for automation:
    • --install-if-missing
    • --yes
    • --channel latest|stable|...

Rationale:

  • A user can install only cocalc first, discover additional products via cocalc --help, and immediately launch UI products with minimal friction.
  • This improves first-run conversion from CLI users to Plus/Launchpad usage.

Sprites CLI Mapping

High-level parity mapping:

  • sprite create -> cocalc project create
  • sprite list -> cocalc project list
  • sprite use -> cocalc project use
  • sprite exec -> cocalc project exec
  • sprite console -> cocalc project console
  • sprite proxy / sprite url -> cocalc project proxy ...
  • sprite checkpoint ... -> cocalc project snapshot ...
  • sprite restore -> cocalc project backup restore-path / snapshot restore-path (with restore-all planned)
  • sprite org/auth -> cocalc auth ... and cocalc org ... (if needed)

CoCalc-specific extension:

  • Explicit first-class host command tree
  • Explicit project placement/move/copy workflows across hosts

Command Grammar and Naming Rules

  • Noun-first: cocalc <noun> <verb> ...
  • Use project consistently.
  • Avoid ambiguous synonyms at launch.
  • Resource identifiers:
    • accept id or exact name
    • require explicit --id in scripts when ambiguity exists

Output Schemas (Stable)

--json success envelope:

{
  "ok": true,
  "command": "project start",
  "data": {"project_id": "...", "op_id": "...", "status": "..."},
  "meta": {"api": "...", "org": "...", "duration_ms": 1234}
}

--json error envelope:

{
  "ok": false,
  "command": "project start",
  "error": {
    "code": "permission_denied",
    "message": "...",
    "details": {}
  },
  "meta": {"request_id": "..."}
}

Implementation Plan (src/packages/cli)

Proposed package structure:

src/packages/cli/
  package.json
  tsconfig.json
  src/
    bin/cocalc.ts
    command-registry.ts
    core/
      api-client.ts
      context.ts
      config.ts
      output.ts
      errors.ts
      wait.ts
    commands/
      auth.ts
      project.ts
      project-files.ts
      project-snapshots.ts
      project-backups.ts
      host.ts
      op.ts
      browser.ts
      jupyter.ts
      chatroom.ts
      config.ts
      doctor.ts
  sea/
    build-static.sh
    build-bundle.sh
    build-sea.sh

Build approach:

  • Follow src/packages/plus SEA model for consistency.
  • Use static bundling (ncc or esbuild) to one JS entrypoint.
  • Ensure all dynamic imports and file references are SEA-safe.

Dependency constraints:

  • allowed: pure JS packages (commander, ascii-table3, picocolors, yaml)
  • avoid: native addons (node-pty, keytar, sqlite3, etc.)

Type Safety and Anti-Drift Requirements

  • CLI command adapters must import and use typed request/response contracts from Conat/hub APIs where available.
  • No untyped stringly-typed JSON plumbing in command handlers unless explicitly wrapped and validated.
  • Add compile-time checks in CLI package build to fail on API signature drift.
  • Add a small contracts layer in src/packages/cli to isolate naming translation (project CLI <-> project backend).

API Adapter Strategy

  • CLI should use a thin adapter layer over existing Conat hub APIs.
  • Keep protocol-specific details out of command handlers.
  • Add minimal new server endpoints only when a workflow cannot be composed safely.

For your proxy smoke use-case, existing APIs appear sufficient:

  • resolve host connection URL
  • issue project-host HTTP auth token
  • compose /{project_id}/proxy/{port}/

Minimal MVP for Smoke Tests (First Implementation Slice)

Implement only these first:

  1. cocalc project create
  2. cocalc project start --wait
  3. cocalc project exec
  4. cocalc project ssh
  5. cocalc project move --host --wait
  6. cocalc project copy-path --wait
  7. cocalc project snapshot create
  8. cocalc project snapshot list
  9. cocalc host resolve-connection
  10. cocalc host issue-http-token
  11. cocalc project proxy url
  12. cocalc project proxy curl

This subset is enough to cleanly express the current smoke flows:

  • two-host move verification
  • cross-project copy verification
  • HTTP proxy deny/allow checks with token bootstrap
  • SSH and exec checks via one CLI surface
  • snapshot smoke checks with fast btrfs semantics

Example Smoke Script Flow (Future)

WS1=$(cocalc project create smoke-a --json | jq -r '.data.project_id')
WS2=$(cocalc project create smoke-b --json | jq -r '.data.project_id')

cocalc project start "$WS1" --wait
cocalc project start "$WS2" --wait

cocalc project exec "$WS1" -- bash -lc 'mkdir -p smoke && echo hello > smoke/a.txt'

cocalc project move "$WS1" --host "$HOST2" --wait

cocalc project copy-path \
  --src-project "$WS1" --src smoke/a.txt \
  --dest-project "$WS2" --dest smoke/copied.txt --wait

cocalc project exec "$WS2" -- cat smoke/copied.txt

URL=$(cocalc project proxy url "$WS1" --port 8000 --json | jq -r '.data.url')
TOKEN=$(cocalc host issue-http-token --host "$HOST2" --project "$WS1" --json | jq -r '.data.token')
cocalc project proxy curl "$WS1" --port 8000 --expect denied
cocalc project proxy curl "$WS1" --port 8000 --token "$TOKEN" --expect ok

Rollout Phases

Phase 0 (smoke-only):

  • Implement MVP commands above.
  • Lock JSON schemas and exit codes.
  • Add CI smoke scripts using CLI.

Phase 1 (general operator usability):

  • add list/get/status/stop/delete command completeness
  • add full snapshot/backup command completeness (including restore-all when backend support lands)
  • add op wait and streaming progress

Phase 2 (polish and broader parity):

  • profile/org UX polish
  • optional keyring backend
  • project sync commands backed by reflect-sync
  • browser session, Jupyter, and chatroom command families
  • autocompletion (bash/zsh/fish)
  • improved table output and paging

Risks and Mitigations

  • Risk: command naming drift between code (project) and UX (project)
    • Mitigation: adapter layer and strict naming tests on CLI help output.
  • Risk: SEA bundle regressions from dynamic module patterns
    • Mitigation: single static entry, minimal dependencies, SEA integration tests.
  • Risk: flaky wait logic around LRO status races
    • Mitigation: support --wait with postcondition verification where needed.

Recommendation

Proceed with src/packages/cli and implement Phase 0 only first.

This gives immediate value for smoke tests while preserving a coherent long-term command model aligned with Sprites-style workflows and CoCalc’s host/project architecture.

Browser Exec: Prod Sandbox (QuickJS-WASM)

Status (implemented first slice):

  • browser exec --posture prod now defaults to a QuickJS-WASM sandbox when policy.allow_raw_exec is not set to true.
  • Raw new Function(...) evaluation remains available only when explicitly opted in via allow_raw_exec=true.

Sandbox execution model:

  • Agent script runs inside QuickJS (isolated from page JS globals).
  • A constrained bridge exposes globalThis.api helpers:
    • api.action(name, payload)
    • api.navigate(...), api.click(...), api.clickAt(...), api.drag(...)
    • api.type(...), api.press(...)
    • api.scrollBy(...), api.scrollTo(...)
    • api.waitForSelector(...), api.waitForUrl(...)
  • Script emits planned actions; host executes them sequentially using existing typed action machinery and policy checks.

Important constraints of this first slice:

  • Runtime uses the Asyncify-capable QuickJS variant (@jitl/quickjs-wasmfile-release-asyncify via quickjs-emscripten-core).
  • Sandbox api.* calls execute immediately through policy-gated host actions and return structured results, so scripts can compose multi-step logic.
  • Determinism and safety still come from typed action allowlists, per-action policy checks, and strict action-count / payload-size caps.

Security posture:

  • In prod posture, this gives a safer default than raw page-context JS.
  • Policy checks still apply per action (project/origin/action allowlists).
  • Additional approvals/guards for destructive actions are still required for full production hardening.