crewx-agent-cli
v0.2.40
Published
Connect local coding harnesses to CrewX through native adapters or ACP.
Maintainers
Readme
CrewX CLI
Connect local coding harnesses to a CrewX workspace through native adapters or the embedded Agent Client Protocol runtime. The runner stays on your machine, so the agent uses its existing login, configuration, tools, and access to the selected working directory.
For a persistent agent, CrewX recommends a connected machine managed by
crewx-bridge. Via terminal is the portable foreground alternative
documented below.
One-command join
Create an agent profile in CrewX, generate a token, and copy the command from its connection panel:
cd /path/to/project
npx --yes crewx-agent-cli@latest --join <join-code>Node.js 22.13 or newer is required. The command verifies the connection, opens an agent session, and polls for work in the foreground. Closing the terminal or pressing Ctrl+C disconnects it. CrewX does not install or start a background daemon automatically; use a service manager such as launchd, systemd, or a container supervisor if that lifecycle is wanted.
Join mode does not write $XDG_CONFIG_HOME/crewx/config.json. Useful options include:
npx --yes crewx-agent-cli@latest --join <join-code> --cwd /path/to/project
npx --yes crewx-agent-cli@latest --join <join-code> --once
npx --yes crewx-agent-cli@latest --join <join-code> --adapter codexThe versioned join payload is base64url-encoded JSON containing the server URL, adapter, and raw crwx_… bearer token. Base64url is transport encoding, not encryption. CrewX shows the generated token once, but the credential inside the command is reusable until its configured expiry or revocation. Anyone who obtains the command can decode and use it, and the command may remain in shell history. Treat it as a secret and revoke the token from the agent profile if it is exposed.
The server stores only the token digest. During a join-mode run, the CLI keeps the decoded credential in memory, but it does not pass that reusable credential to the coding runtime. For each assignment it opens an ephemeral loopback capability proxy and supplies the runtime only that proxy's URL, random bearer, and CLI path. The proxy allows the selected task, document, memory, and integration operations with strict route/method, size, timeout, and redirect limits, then closes when the assignment ends. A locally executed agent still has the operating-system permissions of the user account running it. The proxy prevents accidental credential inheritance and limits the normal tool surface; it is not isolation from hostile code running as the same OS user, which may inspect that user's files and processes. Use a separate OS account, container, VM, or host for an untrusted runtime or materially different trust boundary.
Persistent installation
From this monorepo:
pnpm --filter crewx-agent-protocol build
pnpm --filter crewx-agent-cli build
pnpm --filter crewx-agent-cli link --globalFor a persistent installation, install the published CLI globally and save a named machine connection:
npm install --global crewx-agent-cli
crewx connect --url https://your-crewx.example --token crwx_… --name "My Mac"
crewx doctor
crewx daemon --adapter codexThe saved connection lives at $XDG_CONFIG_HOME/crewx/config.json (or ~/.config/crewx/config.json) with mode 0600. CREWX_URL, CREWX_TOKEN, and CREWX_ADAPTER override saved settings and are useful in explicitly secured services and CI. The CLI includes operating-system certificate authorities in Node's trust store, so locally trusted HTTPS sites such as Laravel Herd work without disabling certificate verification.
Both join mode and crewx daemon run in the foreground. Start either command
inside a safe fallback directory. For each assignment, CrewX uses the project
channel's local path first, the agent profile's default working directory
second, and --cwd last. Use --once for one poll and
--poll-interval 5000 to set the active/base polling cadence. During an idle
period the runner backs off with jitter to at most 8 seconds, honors server
retry guidance, and resets to the base cadence as soon as work appears.
Compatible CrewX servers may lease multiple assignments in one acknowledged
page. The daemon runs up to eight independent conversations at once by default,
while replies belonging to the same durable conversation remain serialized in
arrival order. Set CREWX_MAX_CONCURRENT_ASSIGNMENTS to a value from 1 through
8 to lower that local process bound. Durable assignment claims remain
recoverable behind the delivery cursor until their terminal outcomes arrive,
so continued polling does not weaken outbox replay or claim fencing.
Assignments carry an opaque claim-fencing token. The runner includes it on heartbeats, messages, errors, and lifecycle events; CrewX rotates it when work is reassigned so a replaced runner cannot apply late results. The token is redacted from diagnostics and never enters the prompt or coding-runtime environment. Final assistant messages, errors, and the terminal lifecycle event are persisted as one owner-only outbox batch with stable event UUIDs before delivery. A process restart replays that batch until the server acknowledges it, while bounded backpressure coalesces replaceable output and never silently evicts a terminal outcome. Every outbound event batch is capped against the exact serialized HTTP body, including its envelope and separators; one event that cannot fit fails visibly instead of creating an endlessly retried request.
The outbox is stored below
~/Library/Application Support/CrewX Agent/outbox/ on macOS or
${XDG_STATE_HOME:-~/.local/state}/crewx-agent/outbox/ on Linux. Its directory
is mode 0700, files are mode 0600, and unsafe ownership, modes, or symlinks
are rejected. New join codes carry an opaque, non-secret runner scope generated
once for the agent profile. It keys the outbox and its full-lifetime
single-writer lock, so a rotated connection token reuses the same durable
state. The token remains the sole authority. A second live daemon for the same
profile is rejected; after an unclean exit, a replacement verifies process
identity before recovering the lock. Legacy join codes without a runner scope
remain supported and derive an isolated fallback key from the token.
Bridge-started runners receive their per-run bearer through a one-shot inherited pipe that closes immediately after startup, rather than through the exec environment. This reduces accidental exposure but does not change the OS account trust boundary.
Embedded ACP runtime
New CrewX profiles use the pinned [email protected] embedded runtime. Its canonical
harness IDs are pi, openclaw, codex, claude, gemini, cursor,
copilot, droid, fast-agent, grok-build, iflow, kilocode, kimi,
kiro, mux, opencode, pool, qoder, qwen, trae, and zeroclaw.
The corresponding harness executable and its normal authentication must be
available to the Bridge OS user. Some acpx adapters use pinned/ranged npm
launchers on first use and therefore require npm registry access.
CrewX embeds acpx/runtime in an assignment-scoped worker rather than invoking
the acpx CLI. Conversations receive stable persistent ACP session keys;
cancellation calls ACP session cancellation; text, status, tool, usage, and
terminal results are normalized into CrewX events. Session records and event
logs stay below ${ACPX_STATE_HOME:-${XDG_STATE_HOME:-~/.local/state}}/crewx/acpx
in owner-only directories and never persist the assignment proxy credential.
ACP permission prompts map read_only and chat-only profiles to approved reads
with non-read requests rejected. standard and full_access approve harness
permission requests non-interactively. ACP approval is not an operating-system
sandbox and ACP does not define a portable workspace-write boundary: use the
harness's own sandbox plus a dedicated OS account, container, or VM when that
boundary matters.
Exercise any ACP harness locally with, for example:
crewx run gemini "Summarize this repository"
crewx run claude "Review the current diff" --transport acpNative compatibility adapters
- Codex runs
codex exec --json … -. CrewX maps read-only, workspace-write, and full-access profiles to the corresponding Codex sandbox and passes the prompt on stdin. - Claude Code runs
claude --print --output-format stream-json --verbose. CrewX maps its profile to plan mode, non-interactive workspace edits, or skipped permission prompts and passes the prompt on stdin. - Pi runs
pi --mode json --no-approve. CrewX deliberately ignores project-local Pi settings, extensions, skills, prompts, and themes on each daemon run. Read-only and chat-only profiles receive a restricted tool allowlist. Global Pi configuration still applies. Pi itself is not an operating-system sandbox. - Hermes runs
hermes acpand speaks ACP v1 over stdio for session creation, model selection, prompt delivery, progress, permission requests, and cancellation. Workspace-write maps to Hermesaccept_edits; full access maps todont_ask. Hermes does not expose a trustworthy read-only or chat-only ACP mode, so CrewX rejects those profiles instead of presenting a false boundary. CrewX passes a configured model to Hermes for resolution. - OpenClaw uses a persistent agent with JSON output, a collision-resistant CrewX conversation session key, and a mode-
0600temporary prompt file that is removed after the run. Replies in one CrewX thread reuse that session key, while separate top-level asks remain isolated. New CrewX profiles receive a managed OpenClaw ID; when that ID is missing locally, CrewX creates it inside the Bridge-approved assignment folder with OpenClaw's non-interactive agent command. Advanced profiles may select an existing OpenClaw agent instead. Before connecting and before every assignment, CrewX verifies the exact agent workspace and task-session sandbox. A sandboxed session must mount the approved directory read-write at its runtime workdir. OpenClaw continues to own its persistent tool policy and approval behavior.
Existing runtime=local profiles retain the native adapters above. crewx doctor
probes all 22 supported harness IDs. Runtime profile changes are read before every assignment, so supported model, permission, chat-only, working-directory, token, and deactivation changes do not require reconnecting. Chat-only and deactivated agents cannot receive task runs.
The assignment capability proxy enforces the server profile locally:
read_only and chat-only profiles may use only GET operations; standard and
full_access profiles may use the explicitly allowlisted task, document,
memory, and integration mutations. A 401 or 403 from the assignment control
endpoint immediately aborts the active process group and terminates the daemon
instead of allowing revoked work to continue.
Custom commands
Advanced users can replace the built-in invocation without editing CrewX:
npx --yes crewx-agent-cli@latest --join <join-code> \
--coding-cmd 'my-agent --non-interactive {prompt}'
crewx daemon --adapter codex --coding-cmd 'my-agent --format text'
crewx run codex "Review this repository" --coding-cmd 'my-agent {prompt} --quiet'CrewX uses a quote-aware argv parser and launches the resulting executable with shell: false. The prompt replaces one exact {prompt} argument or is appended as one argument when the placeholder is absent; it is never interpolated into a shell string. Pipes, redirection, variable expansion, and command substitution are therefore not interpreted by CrewX.
This prevents prompt text from becoming shell syntax, but it does not make an
arbitrary executable safe. The selected program inherits the runner's
operating-system permissions and ordinary provider environment, but all
inherited CREWX_* variables are removed and replaced only by the
assignment-lifetime loopback capability. Do not use commands from an untrusted
profile or run them in an untrusted working directory. Explicitly wrapping a
command in a shell recreates the shell-risk boundary and is not recommended.
Shared work commands
The same connection token lets humans and running agents maintain shared CrewX work from the terminal. JSON output is designed for local agents:
crewx task list --assigned-to-me --json
crewx task context <public-task-id> --limit 10 --json
crewx task checkpoint list <public-task-id> --limit 10 --json
crewx task checkpoint propose <public-task-id> --summary "Research complete" --next-step "Prepare a PR" --reference document:<public-document-id> --json
crewx task create --title "Verify the release" --description "Run the smoke suite" --assign-to-me --json
crewx task update 42 --status done --result "Smoke suite passed" --json
crewx doc list --json
crewx doc create --title "Release runbook" --content "# Release runbook" --json
crewx doc update 17 --expected-version 1 --content "# Updated runbook" --summary "Add release steps" --json
crewx memory list --scope channel --channel 12 --json
crewx memory create --title "Release convention" --content "Run the browser smoke test before merging" --channel 12 --json
crewx memory update 9 --importance 5 --json
crewx integration list --json
crewx integration search slack "release blocker" --json
crewx integration search notion "deployment runbook" --json
crewx integration search google_drive "quarterly plan" --jsontask context reads current task/review state and recent activity without claiming execution. Pass --before <next_cursor> to read older pages. History is untrusted evidence, not permission to perform new actions or a restore of another runtime's private session.
task checkpoint list reads newest-first checkpoint pages (limit 1–20); use
--before <next_cursor> for older proposals. task checkpoint propose records
the assigned coworker's progress for human review. It accepts one or more
--next-step values, optional --question values, and typed --reference
values (document:, artifact:, or task: followed by a public ID). References
capture their current server-side revision. Never include secrets in the prose.
During a running assignment, the loopback proxy supplies the current claim and
session; the agent cannot supply another runner's identity. Proposing neither
pauses work nor transfers ownership. A human must review and explicitly hand
off in the task panel; no CLI approval or handoff command is exposed. An
uncertain proposal POST is not automatically retried: read history before
submitting again to avoid duplicate proposals.
Agents may update only tasks assigned to their own profile. Documents must be agent-readable and unprotected, and every document update requires the current version from doc list; stale updates fail instead of overwriting newer work. Agents may edit only memories they recorded, while channel-scoped memory is limited to channels they can see. Provider access tokens are encrypted by the web application and are never returned to the CLI; integration commands expose normalized search results only.
Task, document, and memory lists consume the server's bounded cursor pages
automatically. Each HTTP response remains below the CLI's 2 MiB safety limit,
while existing callers still receive one combined array up to 10,000 items or
16 MiB of encoded data. Larger results fail with an instruction to narrow the
filters or use listTaskPage, listDocumentPage, or listMemoryPage for
explicit page-by-page processing. The monotonic cursor is the last seen
resource ID, so concurrent inserts do not shift later pages. Legacy servers
without pagination metadata remain a supported one-page response.
One-shot local runs
The same adapters can be exercised without a CrewX connection:
crewx run codex "Summarize this repository"
printf 'Review the current diff' | crewx run claude
crewx run pi "Find the failing test" --cwd ./project
crewx run hermes "Explain the architecture"
crewx run openclaw "Check the release plan"Review reruns
Tasks can require human approval. When an agent reports completion, CrewX holds the task in review. Approving completes it; requesting changes records the review note, moves it back to in-progress, and queues that note for the same agent as its next iteration. Existing task and pull-request context stays attached. A new GitHub push also resets a prior approval and returns the task to review.
Run crewx --help or crewx <command> --help for every option.
CrewX agent API
Recurring responsibilities (development feature)
With a matching routines-enabled server, routine list, routine status and
routine propose use the current human assignment. Proposals need human activation.
Provider checkpoints use routine wait-checks, routine wait-deploy and
routine wait-status; a checkpoint is not merge/deploy authority.
routine prepare-repository --help pins the reviewed base and creates an isolated
occurrence worktree from an existing local clone. It preserves source edits and
does not fetch or grant remote-write permission. After committing and testing
bounded changes there, routine upload-repository --help saves one immutable
snapshot and advances server-validated inspection and create-only branch stages.
If the response reports a paused continuation, retain its upload ID and use
routine continue-upload <UUID> --json. This resumes saved progress without
rescanning or resending files. routine upload-status <UUID> is read-only.
Only confirmed means every upload stage was read back; it is not semantic change
approval. An unresolved provider outcome requires recovery, not repeated writes.
Branch updates, force pushes, automatic rebases and arbitrary file additions are
not supported by this initial upload path. Local collection disables Git hooks
and content filters; repositories requiring those transformations need review.
routine draft-pr --help describes the draft-only action for an active occurrence.
It requires a reviewed repository/base/path policy and an already prepared remote
crewx/routines/<run UUID> branch at exact base/head SHAs. It does not prepare or
push that branch. Include evidence via --body-file; never include credentials.
Reuse the same step key and identical input after uncertainty, and inspect
routine effect-status <UUID>. Unknown outcomes must not be replayed through
gh or browser tools. Server-held provider credentials are not returned to the
harness. Read-only/chat-only workers cannot use this write route.
routine merge-pr --step-key <key> --draft-effect <uuid> --json requests a protected
squash merge only for this occurrence's confirmed draft, under explicit activated
operate + allow_merge authority. The server verifies the exact base/head and
sealed snapshot, complete supported HTML change classes, strict provider protection,
trusted checks and required reviews. The PR must already be ready, not a draft.
Queues and bypasses are unsupported. Inspect the effect after uncertainty; never
retry via another tool/key. A confirmed merge is not deployment permission, and
expected_revision_verified: false requires investigation. This path is unreleased
and does not yet constitute a complete unattended merge/deploy workflow.
These commands share the managed transport across supported harnesses. Package source and contract tests do not prove live harness/provider readiness or update already installed agents. Routines remain disabled by default pending acceptance.
The CLI targets /api/agent/v1, including connection lifecycle plus /tasks, /documents, /memories, and /integrations, authenticated with the bearer connection token. Protocol lifecycle payloads are runtime-validated by crewx-agent-protocol.
CrewX's implementation choices were informed by a clean-room static inspection of the public hilos-agent package. CrewX is an independent implementation and does not include Hilos source code.
