Crew Node
Crew Node is the open-source customer-side executor for the Crew ecosystem. It
runs near customer repositories, enforces local execution policy, and exposes
the current Runner ToolBackend compatibility endpoint:
POST /v1/tools/execute
It does not contain autonomous planning, model provider credentials, billing,
credit ledgers, dashboards, or customer account logic.
Requirements
- Bun 1.3+
- Git for
git_status and git_diff
- Docker for the recommended production deployment
- Git for workspace, status, diff, and branch operations
- Optional system
patch binary for the legacy patch alias
Configuration
export CREW_NODE_TOKEN=replace-me
export CREW_WORKSPACE_ROOT=/path/to/repos
export CREW_PORT=4321
export CREW_ALLOWED_COMMANDS=git,bun
export CREW_COMMAND_TIMEOUT_SECONDS=30
export CREW_OUTPUT_MAX_BYTES=65536
export CREW_REQUEST_MAX_BYTES=1000000
export CREW_AUDIT_DIR=.crew-audit
CREW_ALLOWED_COMMANDS is empty by default, so command execution is denied
unless explicitly allowed. Per-request policy can further restrict the env
allowlist, but cannot broaden it.
CREW_SANDBOX=none is the only supported MVP sandbox. docker is reserved for
a later implementation and fails at startup.
Production Docker Run
docker build -t crew-node:local .
mkdir -p workspace .crew-audit
docker run --rm -p 4321:4321 \
-e CREW_NODE_TOKEN=replace-me \
-e CREW_WORKSPACE_ROOT=/workspace \
-e CREW_ALLOWED_COMMANDS=git,bun,npm,pnpm,yarn,node,rg,sed,cat,ls,find,patch \
-e CREW_AUDIT_DIR=/audit \
-v "$PWD/workspace:/workspace" \
-v "$PWD/.crew-audit:/audit" \
crew-node:local
Or use:
CREW_NODE_TOKEN=replace-me docker compose -f docker-compose.example.yml up --build
Publishing
Crew Node is the only public, customer-installed package in the Crew ecosystem.
Publish this repository as open source and publish the npm package after the
validation commands pass:
npm login
npm pack --dry-run
npm publish --access public
Customers install only this service on their VPS or private network. Crew
Runner, Crew Gateway, and Crew Dashboard remain private hosted services run by
Crew.
Local Run
bun install
bun run start
Health check:
curl http://127.0.0.1:4321/healthz
Readiness check:
curl http://127.0.0.1:4321/readyz
Execute a read tool:
curl -s http://127.0.0.1:4321/v1/tools/execute \
-H "Authorization: Bearer $CREW_NODE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"requestId": "demo-read",
"root": ".",
"tool": "read",
"input": { "path": "README.md" }
}'
Tool Request Shape
Runner sends raw ToolBackend calls to POST /v1/tools/execute. Successful
responses are the raw tool result JSON expected by Runner, not wrapped in an
ok/result envelope. Non-2xx responses use a JSON error envelope.
{
"requestId": "optional-string",
"root": "absolute-or-relative-root-under-workspace",
"policy": {
"allowedCommands": ["optional", "override"],
"timeoutSeconds": 30,
"outputMaxBytes": 65536
},
"tool": "read-repo-file",
"input": {}
}
Production Runner tool IDs:
list-repo-files
read-repo-file
read-file-range
outline-file
search-repo
write-repo-file
delete-repo-file
run-command
git-diff
git-status
prepare-workspace
finalize-workspace
read-cumulative-diff
collect-safety-findings
Legacy aliases from the initial MVP remain available for local experiments:
read, search, write, patch, command, git_status, and git_diff.
Runner Integration
Point Crew Runner at this service:
export CREW_EXECUTION_BACKEND=node
export CREW_NODE_URL=http://127.0.0.1:4321
export CREW_NODE_TOKEN=replace-me
export CREW_NODE_REQUIRED=true
The node service enforces the intersection of its local
CREW_ALLOWED_COMMANDS and Runner's per-request policy.allowedCommands.
Per-request policy can restrict local policy, but cannot broaden it.
Security Model
- Bearer tokens are compared with constant-time comparison.
- Paths are resolved under
CREW_WORKSPACE_ROOT; traversal and symlink escapes
are rejected.
- Sensitive files such as
.env, private keys, .npmrc, .netrc, .aws, and
.ssh are hidden from listing and refused on reads.
- File and command output is redacted for common token/key formats before it is
returned.
- Spawned command environments are minimal and do not inherit provider API keys.
run-command returns Runner-style CommandResult records, including
allowed: false for policy-denied commands.
Current Limits
CREW_SANDBOX=none is the production mode for this milestone.
CREW_SANDBOX=docker is recognized but intentionally rejected until
per-command container sandboxing is implemented post-MVP.
- Full node registration, heartbeat, polling, event, and result endpoints are
post-MVP and currently return
501 not_implemented because the current
Runner source only implements POST /v1/tools/execute.
Validation
bun test
bun run typecheck
ruby -e 'require "rexml/document"; ARGV.each { |path| REXML::Document.new(File.read(path)) }' CREW_*.xml
docker build -t crew-node:local .