Local-first terminal coding agent MVP for the xpert platform.
xpertinteractive TTY mode with an inline Ink UI:- inline Ink layout without entering the terminal alternate buffer
- committed history appended into normal terminal scrollback
- denser committed/live block rendering for user, assistant, tool, bash, diff, notices, and inline inspectors
/status,/tools, and/sessionrendered inline from local state as inspector-style history cards- display-width-aware status row, inline permission prompt, and fixed composer
xpert -p "..."single-turn modexpert auth statusxpert doctorxpert doctor --jsonxpert resume [sessionId]xpert sessionsxpert sessions list --jsonxpert sessions delete <selector>xpert sessions prune- Interactive slash commands:
/status/tools/session/exit
- Local tools:
ReadGlobGrepWritePatchBash
GitStatusGitDiff- Local session persistence in
~/.xpert-cli/sessions - Remote fingerprint tracking for
apiUrl,organizationId, andassistantId - Automatic stale remote state clearing when backend / org / assistant config changes
- Safe / moderate / dangerous permission checks
- Local host execution by default, not server-side sandbox execution
- Duplicate tool-call reuse and repeated-call guard inside one turn
Ctrl+Ccancels the current turn and returns toxpert>in interactive mode- Local session management from
~/.xpert-cli/sessions:- list local sessions for the current project, or across all projects
- delete a local session by full id or unique id prefix
- prune older local sessions with an explicit
--yesguard resumerestores the latest local session for the current projectresume <unique-prefix>resolves prefixes only inside the current projectresume <full-session-id>can restore a local session from another project and switches into that session's saved local project context
- Interactive restart /
resumenow replays recent persisted turn history into inline scrollback:- replay comes from the local session file, not a server-side history fetch
- persisted history is a clipped renderable transcript of recent user / assistant / tool / bash / diff / notice output
- replay keeps bounded turn, text, bash, diff, and notice limits instead of storing an unlimited raw log
- Automatic local context injection on every run and resume:
XPERT.md/xpert.mdcontent- current
cwd projectRootgit status --short- recent tool-call summaries
- recent changed files
- Request diagnostics for common backend failures:
- service unreachable / DNS / timeout / connection refused
- auth failure (
401/403) - assistant not found vs remote thread not found
- wrong
XPERT_API_URL, missing route, or protocol mismatch - SSE connect failure, mid-run stream interruption, and resume failure
- Startup preflight for interactive,
-p, andresume:- missing / invalid
XPERT_AGENT_ID - backend/auth/assistant checks before the first turn
- missing / invalid
- Active doctor checks for:
- backend reachability
- auth validity
- assistant existence
- organization header acceptance
- thread creation
From npm:
npm install -g @xpert-ai/xpert-cliFrom source:
cd xpert-cli
pnpm install
pnpm buildCopy .env.example to .env in the xpert-cli root, or export the same variables in your shell.
cp .env.example .envThe CLI loads config in this order:
~/.xpert-cli/config.json.xpert-cli.json.env.env.local- real process env
reasoning output is hidden by default. To debug raw reasoning tokens, set XPERT_CLI_SHOW_REASONING=true.
Optional project config:
{
"approvalMode": "default",
"sandboxMode": "host"
}Save that as .xpert-cli.json in the project root.
Optional user config:
~/.xpert-cli/config.json
Interactive:
pnpm --dir xpert-cli --filter @xpert-ai/xpert-cli devWhen both stdin and stdout are real TTYs, interactive mode now starts an inline Ink app without entering the terminal alternate buffer:
- committed history is appended above the live footer and remains in normal terminal scrollback
- on restart or
resume, the CLI replays the recent clipped turn transcript from the local session into committed history before new input - the current pending turn stays live near the bottom while streamed assistant/tool output is also appended into terminal scrollback during the turn
/status,/tools, and/sessionrender as inline local inspector cards- the permission prompt stays inline with tool / risk / scope context
- the composer and status row stay single-line and clip by terminal display width
The main history surface is now the host terminal scrollback, so terminal mouse-wheel scrolling and the terminal scrollbar work naturally again.
Or after build:
node packages/cli/dist/index.jsSingle prompt:
node packages/cli/dist/index.js -p "Read src/index.ts and summarize it"-p and non-TTY flows keep the existing text renderer and do not start Ink.
Resume latest session:
node packages/cli/dist/index.js resumeResume a specific local session by full id or unique prefix:
node packages/cli/dist/index.js resume 28dfbaccresume semantics:
resumerestores the latest local session for the current projectresume <unique-prefix>resolves prefixes only inside the current projectresume <full-session-id>restores that exact local session globally and uses the resumed session's savedprojectRootandcwd- when
resume <full-session-id>is combined with--cwd, the override must stay inside the resumed session's project; it only overridescwd, neverprojectRoot
Manage local sessions without contacting the backend:
node packages/cli/dist/index.js sessions
node packages/cli/dist/index.js sessions list --json
node packages/cli/dist/index.js sessions delete 28dfbacc
node packages/cli/dist/index.js sessions prune --keep 5 --yesHealth checks:
node packages/cli/dist/index.js doctor
node packages/cli/dist/index.js doctor --json
node packages/cli/dist/index.js auth statusWhen a saved local session points at stale remote run state because XPERT_API_URL, XPERT_ORGANIZATION_ID, or XPERT_AGENT_ID changed, the CLI now keeps the local session history but clears the stale remote threadId, runId, and checkpointId before the next turn.
xpert sessions, xpert sessions list, xpert sessions delete, and xpert sessions prune are local-only commands. They read and mutate files in ~/.xpert-cli/sessions directly and do not require backend reachability or a valid XPERT_AGENT_ID.
Cancel a stuck turn in interactive mode:
Press Ctrl+C once
This cancels the current run or local tool execution and drops back to xpert>.
Inside the Ink interactive TTY UI:
/statusprints inline status output from local runtime state/toolsprints inline tool output from the local registry and session data/sessionprints inline session output from local turn transcripts/exitcloses the interactive session
These commands are resolved locally from runtime state and do not call the model. In interactive mode they render as inline inspector-style history cards; in -p and non-TTY flows, the existing text renderer remains unchanged.
Ctrl+C: cancel the current turn; press again to exitEsc: deny the active permission promptUp/Down: browse input history in the composer- terminal scrollback / mouse wheel / terminal scrollbar: review interactive history
- Start a local
xpert-prothat includes the matching client-tools patch. - Set
XPERT_API_URL,XPERT_API_KEY, andXPERT_AGENT_ID. - Open a git project.
- Run:
node packages/cli/dist/index.js -p "Read package.json and summarize it"- Run:
node packages/cli/dist/index.js -p "Search for TODO and show me where it appears"- Run:
node packages/cli/dist/index.js -p "Change the greeting string in src/demo.ts to Hello from xpert-cli"The CLI should show streamed text, local tool execution, write/patch diff, and store the session locally.
Writecreates a new file only. It creates parent directories when needed, fails if the file already exists, and shows a unified diff from an empty file to the new content.Patchedits existing files with verified, in-memory transforms and shows a unified diff after success.Patchsupports exact string replacement, line-range replacement withstartLineandendLine, and sequentialmultiedits that combine replace and range operations.Patchvalidates every edit before writing, so failed multi-edit requests do not leave partial file changes behind.
pnpm testCovered areas:
- path escape blocking
.git/write blocking- dangerous command detection
- session store persistence
- stream interrupt to tool-call adaptation
- host write and patch execution
- multi-edit atomicity
- duplicate tool-call guard
- turn cancellation wiring
- local context truncation and request injection
- request error normalization for service, auth, URL/protocol, stream, and resume failures
The public npm package name is @xpert-ai/xpert-cli.
- Only
packages/cliis published. The workspace root remains private. - GitHub Actions publishes on tag push
cli-v<version>or manualworkflow_dispatch. - The tag version must match
packages/cli/package.json. - Add
NPM_TOKENto the GitHub repository secrets before publishing.
Local pre-publish verification:
pnpm test
pnpm build
cd packages/cli
npm pack --dry-run
npm pack
TMP_DIR="$(mktemp -d)"
npm install --prefix "$TMP_DIR" -g ./xpert-ai-xpert-cli-$(node -p "require('./package.json').version").tgz
"$TMP_DIR/bin/xpert" --helphostis the only implemented backend.- API key auth only.
- Dynamic local tools depend on the accompanying
xpert-propatch. Patchdoes not support full unified patch syntax; it supports exact replace, line-range replace, and sequential multi-edit only.Writeis create-only and will not overwrite existing files.- Repeated-call protection is per turn, not global across all future sessions.
- Local context is intentionally clipped per run:
XPERT.mdcontent is truncatedgit status --shortis line-limited- recent files and tool-call summaries are count-limited
- The Ink UI is intentionally minimal:
- interactive Ink now runs inline without entering the terminal alternate buffer
- history review is delegated to host terminal scrollback, not a complex in-app viewport
- no mouse support
- no vim mode
- no theme system
- no background shell panel
- no large dialog framework