kortex-cli is a command-line interface for launching and managing AI agents in isolated, reproducible workspaces. It creates runtime-based environments (containers, VMs, or other backends) where agents run with your project source code mounted, automatically configured and ready to use — no manual onboarding or setup required.
The architecture is built around pluggable runtimes. The first supported runtime is Podman, which creates container-based workspaces using a custom Fedora image. Additional runtimes (e.g., MicroVM, Kubernetes) can be added to support other execution environments.
Supported Agents
- Claude Code - Anthropic's official CLI for Claude
- Goose - AI agent for development tasks
- Cursor - AI-powered code editor agent
Key Features
- Isolated workspaces per project, each running in its own runtime instance
- Pluggable runtime system — Podman is the default, with support for adding other runtimes
- Automatic agent configuration (onboarding flags, trusted directories) on workspace creation
- Multi-level configuration: workspace, global, project-specific, and agent-specific settings
- Inject environment variables and mount directories into workspaces at multiple scopes
- Connect to MCP servers and integrate with various LLM providers (including Vertex AI)
- Consistent CLI interface across different agent types and runtimes
- Go 1.26+
- Make
make buildThis creates the kortex-cli binary in the current directory.
# Display help and available commands
./kortex-cli --help
# Execute a specific command
./kortex-cli <command> [flags]To install the binary to your GOPATH/bin for system-wide access:
make install# Run all tests
make test
# Run tests with coverage report
make test-coverageAn AI assistant that can perform tasks autonomously. In kortex-cli, agents are the different AI tools (Claude Code, Goose, Cursor) that can be launched and configured.
The underlying AI model that powers the agents. Examples include Claude (by Anthropic), GPT (by OpenAI), and other language models.
A standardized protocol for connecting AI agents to external data sources and tools. MCP servers provide agents with additional capabilities like database access, API integrations, or file system operations.
The environment where workspaces run. kortex-cli supports multiple runtimes (e.g., Podman containers), allowing workspaces to be hosted on different backends depending on your needs.
Pre-configured capabilities or specialized functions that can be enabled for an agent. Skills extend what an agent can do, such as code review, testing, or specific domain knowledge.
A registered directory containing your project source code and its configuration. Each workspace is tracked by kortex-cli with a unique ID and a human-readable name. Workspaces can be accessed using either their ID or name in all commands (start, stop, remove, terminal).
This scenario demonstrates how to configure Claude Code to use a model hosted on Google Cloud Vertex AI instead of the default Anthropic API. This is useful when you need to use Claude through your Google Cloud organization's billing or compliance setup.
Prerequisites:
- A Google Cloud project with the Vertex AI API enabled and Claude models available
- Google Cloud credentials configured on your host machine (via
gcloud auth application-default login)
Step 1: Configure Claude agent settings
Create or edit ~/.kortex-cli/config/agents.json to add the required environment variables and mount your Google Cloud credentials into the workspace:
{
"claude": {
"environment": [
{
"name": "CLAUDE_CODE_USE_VERTEX",
"value": "1"
},
{
"name": "ANTHROPIC_VERTEX_PROJECT_ID",
"value": "my-gcp-project-id"
},
{
"name": "CLOUD_ML_REGION",
"value": "my-region"
}
],
"mounts": [
{"host": "$HOME/.config/gcloud", "target": "$HOME/.config/gcloud", "ro": true}
]
}
}Fields:
CLAUDE_CODE_USE_VERTEX- Set to1to instruct Claude Code to use Vertex AI instead of the Anthropic APIANTHROPIC_VERTEX_PROJECT_ID- Your Google Cloud project ID where Vertex AI is configuredCLOUD_ML_REGION- The region where Claude is available on Vertex AI (e.g.,us-east5)$HOME/.config/gcloudmounted read-only - Provides the workspace access to your application default credentials
Step 2: Register and start the workspace
# Register a workspace with the Podman runtime and Claude agent
kortex-cli init /path/to/project --runtime podman --agent claude
# Start the workspace (using name or ID)
kortex-cli start my-project
# Connect to the workspace — Claude Code will use Vertex AI automatically
kortex-cli terminal my-projectWhen Claude Code starts, it detects ANTHROPIC_VERTEX_PROJECT_ID and CLOUD_ML_REGION and routes all requests to Vertex AI using the mounted application default credentials.
Sharing local Claude settings (optional)
To reuse your host Claude Code settings (preferences, custom instructions, etc.) inside the workspace, add ~/.claude and ~/.claude.json to the mounts:
{
"claude": {
"environment": [
{
"name": "CLAUDE_CODE_USE_VERTEX",
"value": "1"
},
{
"name": "ANTHROPIC_VERTEX_PROJECT_ID",
"value": "my-gcp-project-id"
},
{
"name": "CLOUD_ML_REGION",
"value": "my-region"
}
],
"mounts": [
{"host": "$HOME/.config/gcloud", "target": "$HOME/.config/gcloud", "ro": true},
{"host": "$HOME/.claude", "target": "$HOME/.claude"},
{"host": "$HOME/.claude.json", "target": "$HOME/.claude.json"}
]
}
}~/.claude contains your Claude Code configuration directory (skills, settings) and ~/.claude.json stores your account and preferences. These are mounted read-write so that changes made inside the workspace (e.g., updated preferences) are persisted back to your host.
Notes:
- Run
gcloud auth application-default loginon your host machine before starting the workspace to ensure valid credentials are available - The
$HOME/.config/gcloudmount is read-only to prevent the workspace from modifying your host credentials - No
ANTHROPIC_API_KEYis needed when using Vertex AI — credentials are provided via the mounted gcloud configuration - To pin a specific Claude model, add a
ANTHROPIC_MODELenvironment variable (e.g.,"claude-opus-4-5")
This scenario demonstrates how to pre-configure Claude Code's settings so that when it starts inside a workspace, it skips the interactive onboarding flow and uses your preferred defaults. kortex-cli automatically handles the onboarding flags, and you can optionally customize other settings like theme preferences.
Automatic Onboarding Skip
When you register a workspace with the Claude agent, kortex-cli automatically:
- Sets
hasCompletedOnboarding: trueto skip the first-run wizard - Sets
hasTrustDialogAccepted: truefor the workspace sources directory (the exact path is determined by the runtime)
This happens automatically for every Claude workspace — no manual configuration required.
Optional: Customize Theme and Other Settings
If you want to customize Claude's theme or other preferences, create default settings:
Step 1: Create the agent settings directory
mkdir -p ~/.kortex-cli/config/claudeStep 2: Write the default Claude settings file
cat > ~/.kortex-cli/config/claude/.claude.json << 'EOF'
{
"theme": "dark-daltonized"
}
EOFFields:
theme- The UI theme for Claude Code (e.g.,"dark","light","dark-daltonized")
You don't need to set hasCompletedOnboarding or hasTrustDialogAccepted — kortex-cli adds these automatically when creating the workspace.
Step 3: Register and start the workspace
# Register a workspace — the settings file is embedded in the container image
kortex-cli init /path/to/project --runtime podman --agent claude
# Start the workspace (using name or ID)
kortex-cli start my-project
# Connect — Claude Code starts directly without onboarding
kortex-cli terminal my-projectWhen init runs, kortex-cli:
- Reads all files from
~/.kortex-cli/config/claude/(e.g., your theme preferences) - Automatically adds
hasCompletedOnboarding: trueand marks the workspace sources directory as trusted (the path is determined by the runtime) - Copies the final merged settings into the container image at
/home/agent/.claude.json
Claude Code finds this file on startup and skips onboarding.
Notes:
- Onboarding is skipped automatically — even if you don't create any settings files, kortex-cli ensures Claude starts without prompts
- The settings are baked into the container image at
inittime, not mounted at runtime — changes to the files on the host require re-registering the workspace to take effect - Any file placed under
~/.kortex-cli/config/claude/is copied into the container home directory, preserving the directory structure (e.g.,~/.kortex-cli/config/claude/.some-tool/configbecomes/home/agent/.some-tool/configinside the container) - This approach keeps your workspace self-contained — other developers using the same project are not affected, and your local
~/.claudedirectory is not exposed inside the container - To apply changes to the settings, remove and re-register the workspace:
kortex-cli remove <workspace-id>thenkortex-cli initagain
This scenario demonstrates how to configure the Goose agent in a kortex-cli workspace using Vertex AI as the backend, covering credential injection, sharing your local gcloud configuration, and pre-configuring the default model.
Goose can use Google Cloud Vertex AI as its backend. Authentication relies on Application Default Credentials (ADC) provided by the gcloud CLI. Mount your local ~/.config/gcloud directory to make your host credentials available inside the workspace, and set the GCP_PROJECT_ID, GCP_LOCATION, and GOOSE_PROVIDER environment variables to tell Goose which project and region to use.
Create or edit ~/.kortex-cli/config/agents.json:
{
"goose": {
"environment": [
{
"name": "GOOSE_PROVIDER",
"value": "gcp_vertex_ai"
},
{
"name": "GCP_PROJECT_ID",
"value": "my-gcp-project"
},
{
"name": "GCP_LOCATION",
"value": "my-region"
}
],
"mounts": [
{"host": "$HOME/.config/gcloud", "target": "$HOME/.config/gcloud", "ro": true}
]
}
}The ~/.config/gcloud directory contains your Application Default Credentials and active account configuration. It is mounted read-only so that credentials are available inside the workspace while the host configuration remains unmodified.
Then register and start the workspace:
# Register a workspace with the Podman runtime and Goose agent
kortex-cli init /path/to/project --runtime podman --agent goose
# Start the workspace
kortex-cli start my-project
# Connect — Goose starts with Vertex AI configured
kortex-cli terminal my-projectTo reuse your host Goose settings (model preferences, provider configuration, etc.) inside the workspace, mount the ~/.config/goose directory.
Edit ~/.kortex-cli/config/agents.json to add the mount alongside the Vertex AI configuration:
{
"goose": {
"environment": [
{
"name": "GOOSE_PROVIDER",
"value": "gcp_vertex_ai"
},
{
"name": "GCP_PROJECT_ID",
"value": "my-gcp-project"
},
{
"name": "GCP_LOCATION",
"value": "my-region"
}
],
"mounts": [
{"host": "$HOME/.config/gcloud", "target": "$HOME/.config/gcloud", "ro": true},
{"host": "$HOME/.config/goose", "target": "$HOME/.config/goose"}
]
}
}The ~/.config/goose directory contains your Goose configuration (settings, model preferences, etc.). It is mounted read-write so that changes made inside the workspace are persisted back to your host.
If you want to pre-configure Goose with default settings without exposing your local ~/.config/goose directory inside the container, create default settings files that are baked into the container image at workspace registration time. This is an alternative to mounting your local Goose settings — use one approach or the other, not both.
Automatic Onboarding Skip
When you register a workspace with the Goose agent, kortex-cli automatically sets GOOSE_TELEMETRY_ENABLED to false in the Goose config file if it is not already defined, so Goose skips its telemetry prompt on first launch.
Step 1: Create the agent settings directory
mkdir -p ~/.kortex-cli/config/goose/.config/gooseStep 2: Write the default Goose settings file
As an example, you can configure the model and enable telemetry:
cat > ~/.kortex-cli/config/goose/.config/goose/config.yaml << 'EOF'
GOOSE_MODEL: "claude-sonnet-4-6"
GOOSE_TELEMETRY_ENABLED: true
EOFFields:
GOOSE_MODEL- The model identifier Goose uses for its AI interactionsGOOSE_TELEMETRY_ENABLED- Whether Goose sends usage telemetry; set totrueto opt in, or omit to have kortex-cli default it tofalse
Step 3: Register and start the workspace
# Register a workspace — the settings file is embedded in the container image
kortex-cli init /path/to/project --runtime podman --agent goose
# Start the workspace
kortex-cli start my-project
# Connect — Goose starts with the configured provider and model
kortex-cli terminal my-projectWhen init runs, kortex-cli:
- Reads all files from
~/.kortex-cli/config/goose/(e.g., your provider and model settings) - Automatically sets
GOOSE_TELEMETRY_ENABLED: falsein.config/goose/config.yamlif the key is not already defined - Copies the final settings into the container image at
/home/agent/.config/goose/config.yaml
Goose finds this file on startup and uses the pre-configured settings without prompting.
Notes:
- Telemetry is disabled automatically — even if you don't create any settings files, kortex-cli ensures Goose starts without the telemetry prompt
- If you prefer to enable telemetry, set
GOOSE_TELEMETRY_ENABLED: truein~/.kortex-cli/config/goose/.config/goose/config.yaml - The settings are baked into the container image at
inittime, not mounted at runtime — changes to the files on the host require re-registering the workspace to take effect - Any file placed under
~/.kortex-cli/config/goose/is copied into the container home directory, preserving the directory structure (e.g.,~/.kortex-cli/config/goose/.config/goose/config.yamlbecomes/home/agent/.config/goose/config.yamlinside the container) - This approach keeps your workspace self-contained — other developers using the same project are not affected, and your local
~/.config/goosedirectory is not exposed inside the container - To apply changes to the settings, remove and re-register the workspace:
kortex-cli remove <workspace-id>thenkortex-cli initagain
This scenario demonstrates how to configure the Cursor agent in a kortex-cli workspace, covering API key injection, sharing your local Cursor settings, and pre-configuring the default model.
Cursor requires a CURSOR_API_KEY environment variable to authenticate with the Cursor service. Rather than embedding the key as plain text, use the secret mechanism to keep credentials out of your configuration files.
Step 1: Create the secret
For the Podman runtime, create the secret once on your host machine using podman secret create:
echo "$CURSOR_API_KEY" | podman secret create cursor-api-key -Step 2: Reference the secret in agent configuration
Create or edit ~/.kortex-cli/config/agents.json to inject the secret as an environment variable for the cursor agent:
{
"cursor": {
"environment": [
{
"name": "CURSOR_API_KEY",
"secret": "cursor-api-key"
}
]
}
}Step 3: Register and start the workspace
# Register a workspace with the Podman runtime and Cursor agent
kortex-cli init /path/to/project --runtime podman --agent cursor
# Start the workspace
kortex-cli start my-project
# Connect — Cursor starts with the API key available
kortex-cli terminal my-projectThe secret name (cursor-api-key) must match the secret field value in your configuration. At workspace creation time, kortex-cli passes the secret to Podman, which injects it as the CURSOR_API_KEY environment variable inside the container.
To reuse your host Cursor settings (preferences, keybindings, extensions configuration, etc.) inside the workspace, mount the ~/.cursor directory.
Edit ~/.kortex-cli/config/agents.json to add the mount:
{
"cursor": {
"environment": [
{
"name": "CURSOR_API_KEY",
"secret": "cursor-api-key"
}
],
"mounts": [
{"host": "$HOME/.cursor", "target": "$HOME/.cursor"}
]
}
}The ~/.cursor directory contains your Cursor configuration (settings, model preferences, etc.). It is mounted read-write so that changes made inside the workspace are persisted back to your host.
If you want to pre-configure Cursor with default settings without exposing your local ~/.cursor directory inside the container, create default settings files that are baked into the container image at workspace registration time. This is an alternative to mounting your local Cursor settings — use one approach or the other, not both.
Automatic Onboarding Skip
When you register a workspace with the Cursor agent, kortex-cli automatically creates a .workspace-trusted file in the Cursor projects directory for the workspace sources path, so Cursor skips its workspace trust dialog on first launch.
Step 1: Configure the agent environment
Create or edit ~/.kortex-cli/config/agents.json to inject the API key. No mount is needed since settings are baked in:
{
"cursor": {
"environment": [
{
"name": "CURSOR_API_KEY",
"secret": "cursor-api-key"
}
]
}
}Step 2: Create the agent settings directory
mkdir -p ~/.kortex-cli/config/cursor/.cursorStep 3: Write the default Cursor settings file
As an example, you can configure a default model:
cat > ~/.kortex-cli/config/cursor/.cursor/cli-config.json << 'EOF'
{
"model": {
"modelId": "claude-4.5-opus-high-thinking",
"displayModelId": "claude-4.5-opus-high-thinking",
"displayName": "Opus 4.5 Thinking",
"displayNameShort": "Opus 4.5 Thinking",
"aliases": [
"opus",
"opus-4.5",
"opus-4-5"
],
"maxMode": false
},
"hasChangedDefaultModel": true
}
EOFFields:
model.modelId- The model identifier used internally by Cursormodel.displayName/model.displayNameShort- Human-readable model names shown in the UImodel.aliases- Shorthand names that can be used to reference the modelmodel.maxMode- Whether to enable max mode for this modelhasChangedDefaultModel- Tells Cursor that the model selection is intentional and should not prompt the user to choose a model
Step 4: Register and start the workspace
# Register a workspace — the settings file is embedded in the container image
kortex-cli init /path/to/project --runtime podman --agent cursor
# Start the workspace
kortex-cli start my-project
# Connect — Cursor starts with the configured model
kortex-cli terminal my-projectWhen init runs, kortex-cli:
- Reads all files from
~/.kortex-cli/config/cursor/(e.g., your model settings) - Automatically creates the workspace trust file so Cursor skips its trust dialog
- Copies the final settings into the container image at
/home/agent/.cursor/cli-config.json
Cursor finds this file on startup and uses the pre-configured model without prompting.
Notes:
- The settings are baked into the container image at
inittime, not mounted at runtime — changes to the files on the host require re-registering the workspace to take effect - Any file placed under
~/.kortex-cli/config/cursor/is copied into the container home directory, preserving the directory structure (e.g.,~/.kortex-cli/config/cursor/.cursor/cli-config.jsonbecomes/home/agent/.cursor/cli-config.jsoninside the container) - To apply changes to the settings, remove and re-register the workspace:
kortex-cli remove <workspace-id>thenkortex-cli initagain - This approach keeps your workspace self-contained — other developers using the same project are not affected, and your local
~/.cursordirectory is not exposed inside the container - Do not combine this approach with the
~/.cursormount from the previous section — the mounted directory would override the baked-in defaults at runtime
This scenario demonstrates how to make a GitHub token available inside workspaces using the multi-level configuration system — either globally for all projects or scoped to a specific project.
For all projects
Edit ~/.kortex-cli/config/projects.json and add the token and your git configuration under the global "" key:
{
"": {
"environment": [
{
"name": "GH_TOKEN",
"secret": "github-token"
}
],
"mounts": [
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig", "ro": true}
]
}
}The GH_TOKEN variable is automatically picked up by the gh CLI and other GitHub-aware tools running inside the workspace. The $HOME/.gitconfig mount makes your git identity (name, email, aliases, etc.) available to git commands run by the agent.
For a specific project
Use the project identifier as the key instead. The identifier is the git remote URL (without .git) as detected by kortex-cli during init:
{
"https://github.com/my-org/my-repo/": {
"environment": [
{
"name": "GH_TOKEN",
"secret": "github-token"
}
]
}
}This injects the token only when working on workspaces that belong to https://github.com/my-org/my-repo/, leaving other projects unaffected.
Both at once
You can combine global and project-specific entries in the same file. The project-specific value takes precedence over the global one if both define the same variable:
{
"": {
"environment": [
{
"name": "GH_TOKEN",
"secret": "github-token-default"
}
]
},
"https://github.com/my-org/my-private-repo/": {
"environment": [
{
"name": "GH_TOKEN",
"secret": "github-token-private"
}
]
}
}Creating the secret
How secrets are created depends on the runtime being used. The secret field value is the name under which the secret is registered with that runtime.
For the Podman runtime, create the secret once on your host machine using podman secret create before registering the workspace:
# Create the secret from an environment variable
echo "$GITHUB_TOKEN" | podman secret create github-token -
# Or create it from a file
podman secret create github-token /path/to/token-fileThe secret name (github-token here) must match the secret field value in your configuration. At workspace creation time, kortex-cli passes --secret github-token,type=env,target=GH_TOKEN to Podman, which injects the secret value as the GH_TOKEN environment variable inside the container.
Podman secrets are stored locally on the host and never written to the container image.
Notes:
- The
secretfield references a secret by name rather than embedding the token value directly, keeping credentials out of the configuration file - The project identifier used as the key must match what kortex-cli detected during
init— runkortex-cli list -o jsonto see the project field for each registered workspace - Configuration changes in
projects.jsontake effect the next time you runkortex-cli initfor that workspace; already-registered workspaces need to be removed and re-registered
This scenario demonstrates how to run multiple agents in parallel, each working on a different branch of the same repository. Git worktrees allow each branch to live in its own directory, so each agent gets its own isolated workspace.
Step 1: Clone the repository
git clone https://github.com/my-org/my-repo.git /path/to/my-project/mainStep 2: Create a worktree for each feature branch
cd /path/to/my-project/main
git worktree add ../feature-a feature-a
git worktree add ../feature-b feature-bThis results in the following layout:
/path/to/my-project/
├── main/ ← main branch (original clone)
├── feature-a/ ← feature-a branch (worktree)
└── feature-b/ ← feature-b branch (worktree)
Step 3: Configure the main branch mount in your local project config
If you want the agents to have access to the main branch (e.g., to compare changes), add the mount in ~/.kortex-cli/config/projects.json under the project identifier. This keeps the configuration on your machine only — not all developers of the project may use worktrees, so it does not belong in the repository's .kortex/workspace.json.
{
"https://github.com/my-org/my-repo/": {
"mounts": [
{"host": "$SOURCES/../main", "target": "$SOURCES/../main"}
]
}
}$SOURCES expands to the workspace sources directory (e.g., /path/to/my-project/feature-a), so $SOURCES/../main resolves to /path/to/my-project/main on both the host and inside the container.
Step 4: Register a workspace for each worktree
kortex-cli init /path/to/my-project/feature-a --runtime podman --agent claude
kortex-cli init /path/to/my-project/feature-b --runtime podman --agent claudeStep 5: Start and connect to each workspace independently
# Start both workspaces (using names or IDs)
kortex-cli start feature-a
kortex-cli start feature-b
# Connect to each agent in separate terminals
kortex-cli terminal feature-a
kortex-cli terminal feature-bEach agent runs independently in its own container, operating on its own branch without interfering with the other.
Notes:
- Each worktree shares the same
.gitdirectory, so agents can run git commands that are branch-aware - Workspaces for different worktrees of the same repository share the same project identifier (derived from the git remote URL), so the mount defined in
projects.jsonautomatically applies to all of them
This scenario demonstrates how to manage workspaces programmatically using JSON output, which is ideal for UIs, scripts, or automation tools. All commands support the --output json (or -o json) flag for machine-readable output.
Step 1: Check existing workspaces
$ kortex-cli workspace list -o json{
"items": []
}Exit code: 0 (success, but no workspaces registered)
Step 2: Register a new workspace
$ kortex-cli init /path/to/project --runtime podman --agent claude -o json{
"id": "2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea"
}Exit code: 0 (success)
Step 3: Register with verbose output to get full details
$ kortex-cli init /path/to/another-project --runtime podman --agent claude -o json -v{
"id": "f6e5d4c3b2a1098765432109876543210987654321098765432109876543210a",
"name": "another-project",
"agent": "claude",
"project": "/absolute/path/to/another-project",
"state": "stopped",
"paths": {
"source": "/absolute/path/to/another-project",
"configuration": "/absolute/path/to/another-project/.kortex"
}
}Exit code: 0 (success)
Step 3a: Register and start immediately with auto-start flag
$ kortex-cli init /path/to/third-project --runtime podman --agent claude -o json --start{
"id": "3c4d5e6f7a8b9098765432109876543210987654321098765432109876543210b"
}Exit code: 0 (success, workspace is running)
Step 4: List all workspaces
$ kortex-cli workspace list -o json{
"items": [
{
"id": "2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea",
"name": "project",
"agent": "claude",
"project": "/absolute/path/to/project",
"state": "running",
"paths": {
"source": "/absolute/path/to/project",
"configuration": "/absolute/path/to/project/.kortex"
}
},
{
"id": "f6e5d4c3b2a1098765432109876543210987654321098765432109876543210a",
"name": "another-project",
"agent": "claude",
"project": "/absolute/path/to/another-project",
"state": "stopped",
"paths": {
"source": "/absolute/path/to/another-project",
"configuration": "/absolute/path/to/another-project/.kortex"
}
}
]
}Exit code: 0 (success)
Step 5: Start a workspace
$ kortex-cli workspace start 2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea -o json{
"id": "2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea"
}Exit code: 0 (success)
Step 6: Stop a workspace
$ kortex-cli workspace stop 2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea -o json{
"id": "2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea"
}Exit code: 0 (success)
Step 7: Remove a workspace
$ kortex-cli workspace remove 2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea -o json{
"id": "2c5f16046476be368fcada501ac6cdc6bbd34ea80eb9ceb635530c0af64681ea"
}Exit code: 0 (success)
Step 8: Verify removal
$ kortex-cli workspace list -o json{
"items": [
{
"id": "f6e5d4c3b2a1098765432109876543210987654321098765432109876543210a",
"name": "another-project",
"agent": "claude",
"project": "/absolute/path/to/another-project",
"state": "stopped",
"paths": {
"source": "/absolute/path/to/another-project",
"configuration": "/absolute/path/to/another-project/.kortex"
}
}
]
}Exit code: 0 (success)
All errors are returned in JSON format when using --output json, with the error written to stdout (not stderr) and a non-zero exit code.
Error: Non-existent directory
$ kortex-cli init /tmp/no-exist --runtime podman --agent claude -o json{
"error": "sources directory does not exist: /tmp/no-exist"
}Exit code: 1 (error)
Error: Workspace not found
$ kortex-cli workspace remove unknown-id -o json{
"error": "workspace not found: unknown-id"
}Exit code: 1 (error)
- Always check the exit code to determine success (0) or failure (non-zero)
- Parse stdout for JSON output in both success and error cases
- Use verbose mode with init (
-v) when you need full workspace details immediately after creation - Handle both success and error JSON structures in your code:
- Success responses have specific fields (e.g.,
id,items,name,paths) - Error responses always have an
errorfield
- Success responses have specific fields (e.g.,
Example script pattern:
#!/bin/bash
# Register a workspace
output=$(kortex-cli init /path/to/project --runtime podman --agent claude -o json)
exit_code=$?
if [ $exit_code -eq 0 ]; then
workspace_id=$(echo "$output" | jq -r '.id')
echo "Workspace created: $workspace_id"
else
error_msg=$(echo "$output" | jq -r '.error')
echo "Error: $error_msg"
exit 1
fikortex-cli supports environment variables for configuring default behavior.
Sets the default runtime to use when registering a workspace with the init command.
Usage:
export KORTEX_CLI_DEFAULT_RUNTIME=fake
kortex-cli init /path/to/project --agent claudePriority:
The runtime is determined in the following order (highest to lowest priority):
--runtimeflag (if specified)KORTEX_CLI_DEFAULT_RUNTIMEenvironment variable (if set)- Error if neither is set (runtime is required)
Example:
# Set the default runtime for the current shell session
export KORTEX_CLI_DEFAULT_RUNTIME=fake
# Register a workspace using the environment variable
kortex-cli init /path/to/project --agent claude
# Override the environment variable with the flag
kortex-cli init /path/to/another-project --agent claude --runtime podmanNotes:
- The runtime parameter is mandatory when registering workspaces
- If neither the flag nor the environment variable is set, the
initcommand will fail with an error - Supported runtime types depend on the available runtime implementations
- Setting this environment variable is useful for automation scripts or when you consistently use the same runtime
Sets the default agent to use when registering a workspace with the init command.
Usage:
export KORTEX_CLI_DEFAULT_AGENT=claude
kortex-cli init /path/to/project --runtime podmanPriority:
The agent is determined in the following order (highest to lowest priority):
--agentflag (if specified)KORTEX_CLI_DEFAULT_AGENTenvironment variable (if set)- Error if neither is set (agent is required)
Example:
# Set the default agent for the current shell session
export KORTEX_CLI_DEFAULT_AGENT=claude
# Register a workspace using the environment variable
kortex-cli init /path/to/project --runtime podman
# Override the environment variable with the flag
kortex-cli init /path/to/another-project --runtime podman --agent gooseNotes:
- The agent parameter is mandatory when registering workspaces
- If neither the flag nor the environment variable is set, the
initcommand will fail with an error - Supported agent types depend on the available agent configurations in the runtime
- Agent names must contain only alphanumeric characters or underscores (e.g.,
claude,goose,my_agent) - Setting this environment variable is useful for automation scripts or when you consistently use the same agent
Sets the default storage directory where kortex-cli stores its data files.
Usage:
export KORTEX_CLI_STORAGE=/custom/path/to/storage
kortex-cli init /path/to/project --runtime podman --agent claudePriority:
The storage directory is determined in the following order (highest to lowest priority):
--storageflag (if specified)KORTEX_CLI_STORAGEenvironment variable (if set)- Default:
$HOME/.kortex-cli
Example:
# Set a custom storage directory
export KORTEX_CLI_STORAGE=/var/lib/kortex
# All commands will use this storage directory
kortex-cli init /path/to/project --runtime podman --agent claude
kortex-cli list
# Override the environment variable with the flag
kortex-cli list --storage /tmp/kortex-storageAutomatically starts a workspace after registration when using the init command.
Usage:
export KORTEX_CLI_INIT_AUTO_START=1
kortex-cli init /path/to/project --runtime podman --agent claudePriority:
The auto-start behavior is determined in the following order (highest to lowest priority):
--startflag (if specified)KORTEX_CLI_INIT_AUTO_STARTenvironment variable (if set to a truthy value)- Default: workspace is not started automatically
Supported Values:
The environment variable accepts the following truthy values (case-insensitive):
1true,True,TRUEyes,Yes,YES
Any other value (including 0, false, no, or empty string) will not trigger auto-start.
Example:
# Set auto-start for the current shell session
export KORTEX_CLI_INIT_AUTO_START=1
# Register and start a workspace automatically
kortex-cli init /path/to/project --runtime podman --agent claude
# Workspace is now running
# Override the environment variable with the flag
export KORTEX_CLI_INIT_AUTO_START=0
kortex-cli init /path/to/another-project --runtime podman --agent claude --start
# Workspace is started despite env var being 0Notes:
- Auto-starting combines the
initandstartcommands into a single operation - Useful for automation scripts where you want workspaces ready to use immediately
- If the workspace fails to start, the registration still succeeds, but an error is returned
- The
--startflag always takes precedence over the environment variable
The Podman runtime provides a container-based development environment for workspaces. It creates an isolated environment with all necessary tools pre-installed and configured.
Base Image: registry.fedoraproject.org/fedora:latest
The Podman runtime builds a custom container image based on Fedora Linux, providing a stable and up-to-date foundation for development work.
The runtime includes a comprehensive development toolchain:
-
Core Utilities:
which- Command location utilityprocps-ng- Process management utilitieswget2- Advanced file downloader
-
Development Tools:
@development-tools- Complete development toolchain (gcc, make, etc.)jq- JSON processorgh- GitHub CLI
-
Language Support:
golang- Go programming languagegolangci-lint- Go linterpython3- Python 3 interpreterpython3-pip- Python package manager
The container runs as a non-root user named agent with the following configuration:
- User:
agent - UID/GID: Matches the host user's UID and GID for seamless file permissions
- Home Directory:
/home/agent
Sudo Permissions:
The agent user has limited sudo access with no password required (NOPASSWD) for:
-
Package Management:
/usr/bin/dnf- Install, update, and manage packages
-
Process Management:
/bin/nice- Run programs with modified scheduling priority/bin/kill,/usr/bin/kill- Send signals to processes/usr/bin/killall- Kill processes by name
All other sudo commands are explicitly denied for security.
The Podman runtime includes default configurations for the following AI agents:
Claude Code - Installed using the official installation script from claude.ai/install.sh:
- Full Claude Code CLI capabilities
- Integrated development assistance
- Access to Claude's latest features
Goose - Installed using the official installer from github.com/block/goose:
- AI-powered development agent
- Task automation and code assistance
- Configurable development workflows
The agent runs within the container environment and has access to the mounted workspace sources and dependencies.
The container's working directory is set to /workspace/sources, which is where your project source code is mounted. This ensures that the agent and all tools operate within your project context.
# Register a workspace with the Podman runtime
kortex-cli init /path/to/project --runtime podman --agent claudeUser Experience:
When you register a workspace with the Podman runtime, you'll see progress feedback for each operation:
⠋ Creating temporary build directory
✓ Temporary build directory created
⠋ Generating Containerfile
✓ Containerfile generated
⠋ Building container image: kortex-cli-myproject
✓ Container image built
⠋ Creating container: myproject
✓ Container created
The init command will:
- Create a temporary build directory - with progress spinner
- Generate a Containerfile with the configuration above - with progress spinner
- Build a custom image (tagged as
kortex-cli-<workspace-name>) - with progress spinner - Create a container with your source code mounted - with progress spinner
After registration, you can start the workspace:
# Start the workspace
kortex-cli start <workspace-id>Note: When using --output json, all progress spinners are hidden to avoid polluting the JSON output.
The Podman runtime is fully configurable through JSON files. When you first use the Podman runtime, default configuration files are automatically created in your storage directory.
Configuration Location:
$HOME/.kortex-cli/runtimes/podman/config/
├── image.json # Base image configuration
├── claude.json # Claude agent configuration
└── goose.json # Goose agent configuration
Or if using a custom storage directory:
<storage-dir>/runtimes/podman/config/
Controls the container's base image, packages, and sudo permissions.
Structure:
{
"version": "latest",
"packages": [
"which",
"procps-ng",
"wget2",
"@development-tools",
"jq",
"gh",
"golang",
"golangci-lint",
"python3",
"python3-pip"
],
"sudo": [
"/usr/bin/dnf",
"/bin/nice",
"/bin/kill",
"/usr/bin/kill",
"/usr/bin/killall"
],
"run_commands": []
}Fields:
-
version(required) - Fedora version tag- Examples:
"latest","40","41" - The base registry
registry.fedoraproject.org/fedorais hardcoded and cannot be changed
- Examples:
-
packages(optional) - DNF packages to install- Array of package names
- Can include package groups with
@prefix (e.g.,"@development-tools") - Empty array is valid if no packages needed
-
sudo(optional) - Binaries theagentuser can run with sudo- Must be absolute paths (e.g.,
"/usr/bin/dnf") - Creates a single
ALLOWEDcommand alias in sudoers - Empty array disables all sudo access
- Must be absolute paths (e.g.,
-
run_commands(optional) - Custom shell commands to run during image build- Executed as RUN instructions in the Containerfile
- Run before agent-specific commands
- Useful for additional setup steps
Controls agent-specific packages and installation steps. The Podman runtime provides default configurations for Claude Code (claude.json) and Goose (goose.json).
Structure (claude.json):
{
"packages": [],
"run_commands": [
"curl -fsSL --proto-redir '-all,https' --tlsv1.3 https://claude.ai/install.sh | bash",
"mkdir -p /home/agent/.config"
],
"terminal_command": [
"claude"
]
}Structure (goose.json):
{
"packages": [],
"run_commands": [
"cd /tmp && curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash"
],
"terminal_command": [
"goose"
]
}Fields:
-
packages(optional) - Additional packages specific to this agent- Merged with packages from
image.json - Useful for agent-specific dependencies
- Merged with packages from
-
run_commands(optional) - Commands to set up the agent- Executed after image configuration commands
- Typically used for agent installation
-
terminal_command(required) - Command to launch the agent- Must have at least one element
- Can include flags:
["claude", "--verbose"]
Configuration changes take effect when you register a new workspace with init. The Containerfile is generated and the image is built during workspace registration, using the configuration files that exist at that time.
To apply new configuration:
-
Edit the configuration files:
# Edit base image configuration nano ~/.kortex-cli/runtimes/podman/config/image.json # Edit agent configuration (use the agent you want) nano ~/.kortex-cli/runtimes/podman/config/claude.json # or nano ~/.kortex-cli/runtimes/podman/config/goose.json
-
Register a new workspace (this creates the Containerfile and builds the image):
# Using Claude agent kortex-cli init /path/to/project --runtime podman --agent claude # or using Goose agent kortex-cli init /path/to/project --runtime podman --agent goose
-
Start the workspace:
kortex-cli start <workspace-id>
Notes:
- The first
initcommand using Podman creates default config files automatically - Config files are never overwritten once created - your customizations are preserved
- The Containerfile and image are built during
init, notstart - Each workspace's image is built once using the configuration at registration time
- To rebuild a workspace with new config, remove and re-register it
- Validation errors in config files will cause workspace registration to fail with a descriptive message
- The generated Containerfile is automatically copied to
/home/agent/Containerfileinside the container for reference
Each workspace can optionally include a configuration file that customizes the environment and mount behavior for that specific workspace. The configuration is stored in a workspace.json file within the workspace's configuration directory (typically .kortex in the sources directory).
By default, workspace configuration is stored at:
<sources-directory>/.kortex/workspace.json
The configuration directory (containing workspace.json) can be customized using the --workspace-configuration flag when registering a workspace with init. The flag accepts a directory path, not the file path itself.
The workspace.json file uses a nested JSON structure:
{
"environment": [
{
"name": "DEBUG",
"value": "true"
},
{
"name": "API_KEY",
"secret": "github-token"
}
],
"mounts": [
{"host": "$SOURCES/../main", "target": "$SOURCES/../main"},
{"host": "$HOME/.ssh", "target": "$HOME/.ssh"},
{"host": "/absolute/path/to/data", "target": "/workspace/data"}
]
}Define environment variables that will be set in the workspace runtime environment.
Structure:
{
"environment": [
{
"name": "VAR_NAME",
"value": "hardcoded-value"
},
{
"name": "SECRET_VAR",
"secret": "secret-reference"
}
]
}Fields:
name(required) - Environment variable name- Must be a valid Unix environment variable name
- Must start with a letter or underscore
- Can contain letters, digits, and underscores
value(optional) - Hardcoded value for the variable- Mutually exclusive with
secret - Empty strings are allowed
- Mutually exclusive with
secret(optional) - Reference to a secret containing the value- Mutually exclusive with
value - Cannot be empty
- Mutually exclusive with
Validation Rules:
- Variable name cannot be empty
- Exactly one of
valueorsecretmust be defined - Variable names must follow Unix conventions (e.g.,
DEBUG,API_KEY,MY_VAR_123) - Invalid names include those starting with digits (
1INVALID) or containing special characters (INVALID-NAME,INVALID@NAME)
Configure additional directories to mount in the workspace runtime.
Structure:
{
"mounts": [
{"host": "$SOURCES/../main", "target": "$SOURCES/../main"},
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"},
{"host": "/absolute/path/to/data", "target": "/workspace/data", "ro": true}
]
}Fields:
host(required) - Path on the host filesystem to mounttarget(required) - Path inside the container where the host path is mountedro(optional) - Mount as read-only (default:false)
Path Variables:
Both host and target support the following variables:
$SOURCES- Expands to the workspace sources directory on the host, or/workspace/sourcesin the container$HOME- Expands to the user's home directory on the host, or/home/agentin the container
Paths can also be absolute (e.g., /absolute/path).
Validation Rules:
hostandtargetcannot be empty- Each path must be absolute or start with
$SOURCESor$HOME $SOURCES-based container targets must not escape above/workspace$HOME-based container targets must not escape above/home/agent
When you register a workspace with kortex-cli init, the configuration is automatically validated. If workspace.json exists and contains invalid data, the registration will fail with a descriptive error message.
Example - Invalid configuration (both value and secret set):
$ kortex-cli init /path/to/project --runtime podman --agent claudeError: workspace configuration validation failed: invalid workspace configuration:
environment variable "API_KEY" (index 0) has both value and secret set
Example - Invalid configuration (missing host in mount):
$ kortex-cli init /path/to/project --runtime podman --agent claudeError: workspace configuration validation failed: invalid workspace configuration:
mount at index 0 is missing host
Basic environment variables:
{
"environment": [
{
"name": "NODE_ENV",
"value": "development"
},
{
"name": "DEBUG",
"value": "true"
}
]
}Using secrets:
{
"environment": [
{
"name": "API_TOKEN",
"secret": "github-api-token"
}
]
}git worktree:
{
"mounts": [
{"host": "$SOURCES/../main", "target": "$SOURCES/../main"}
]
}Sharing user configurations:
{
"mounts": [
{"host": "$HOME/.claude", "target": "$HOME/.claude"},
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"},
{"host": "$HOME/.kube/config", "target": "$HOME/.kube/config", "ro": true}
]
}Complete configuration:
{
"environment": [
{
"name": "NODE_ENV",
"value": "development"
},
{
"name": "DATABASE_URL",
"secret": "local-db-url"
}
],
"mounts": [
{"host": "$SOURCES/../main", "target": "$SOURCES/../main"},
{"host": "$HOME/.claude", "target": "$HOME/.claude"},
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"}
]
}- Configuration is optional - workspaces can be registered without a
workspace.jsonfile - The configuration file is validated only when it exists
- Validation errors are caught early during workspace registration (
initcommand) - All validation rules are enforced to prevent runtime errors
- The configuration model is imported from the
github.com/kortex-hub/kortex-cli-api/workspace-configuration/gopackage for consistency across tools
kortex-cli supports configuration at multiple levels, allowing you to customize workspace settings for different contexts. Configurations are automatically merged with proper precedence, making it easy to share common settings while still allowing project and agent-specific customization.
1. Workspace Configuration (.kortex/workspace.json)
- Stored in your project repository
- Shared with all developers
- Used by all agents
- Committed to version control
2. Global Project Configuration (~/.kortex-cli/config/projects.json with "" key)
- User-specific settings applied to all projects
- Stored on your local machine (not committed to git)
- Perfect for common settings like
.gitconfig, SSH keys, or global environment variables - Never shared with other developers
3. Project-Specific Configuration (~/.kortex-cli/config/projects.json)
- User-specific settings for a specific project
- Stored on your local machine (not committed to git)
- Overrides global settings for this project
- Identified by project ID (git repository URL or directory path)
4. Agent-Specific Configuration (~/.kortex-cli/config/agents.json)
- User-specific settings for a specific agent (Claude, Goose, etc.)
- Stored on your local machine (not committed to git)
- Overrides all other configurations
- Perfect for agent-specific environment variables or tools
When registering a workspace, configurations are merged in this order (later configs override earlier ones):
- Workspace (
.kortex/workspace.json) - Base configuration from repository - Global (projects.json
""key) - Your global settings for all projects - Project (projects.json specific project) - Your settings for this project
- Agent (agents.json specific agent) - Your settings for this agent
Example: If DEBUG is defined in workspace config as false, in project config as true, and in agent config as verbose, the final value will be verbose (from agent config).
User-specific configurations are stored in the kortex-cli storage directory:
- Default location:
~/.kortex-cli/config/ - Custom location: Set via
--storageflag orKORTEX_CLI_STORAGEenvironment variable
The storage directory contains:
config/agents.json- Agent-specific environment variables and mountsconfig/projects.json- Project-specific and global environment variables and mountsconfig/<agent>/- Agent default settings files (e.g.,config/claude/.claude.json)
Location: ~/.kortex-cli/config/agents.json
Format:
{
"claude": {
"environment": [
{
"name": "DEBUG",
"value": "true"
}
],
"mounts": [
{"host": "$HOME/.claude-config", "target": "$HOME/.claude-config"}
]
},
"goose": {
"environment": [
{
"name": "GOOSE_MODE",
"value": "verbose"
}
]
}
}Each key is an agent name (e.g., claude, goose). The value uses the same structure as workspace.json.
Location: ~/.kortex-cli/config/projects.json
Format:
{
"": {
"mounts": [
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"},
{"host": "$HOME/.ssh", "target": "$HOME/.ssh"}
]
},
"github.com/kortex-hub/kortex-cli": {
"environment": [
{
"name": "PROJECT_VAR",
"value": "project-value"
}
],
"mounts": [
{"host": "$SOURCES/../kortex-common", "target": "$SOURCES/../kortex-common"}
]
},
"/home/user/my/project": {
"environment": [
{
"name": "LOCAL_DEV",
"value": "true"
}
]
}
}Special Keys:
- Empty string
""- Global configuration applied to all projects - Git repository URL - Configuration for all workspaces in that repository (e.g.,
github.com/user/repo) - Directory path - Configuration for a specific directory (takes precedence over repository URL)
Global Settings for All Projects:
{
"": {
"mounts": [
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"},
{"host": "$HOME/.ssh", "target": "$HOME/.ssh"},
{"host": "$HOME/.gnupg", "target": "$HOME/.gnupg"}
]
}
}This mounts your git config and SSH keys in every workspace you create.
Project-Specific API Keys:
{
"github.com/company/project": {
"environment": [
{
"name": "API_KEY",
"secret": "project-api-key"
}
]
}
}This adds an API key only for workspaces in the company project.
Agent-Specific Debug Mode:
{
"claude": {
"environment": [
{
"name": "DEBUG",
"value": "true"
}
]
}
}This enables debug mode only when using the Claude agent.
Register workspace with agent-specific config:
kortex-cli init --runtime podman --agent claudeRegister workspace with custom project:
kortex-cli init --runtime podman --project my-custom-project --agent gooseNote: The --agent flag is required (or set KORTEX_CLI_DEFAULT_AGENT environment variable) when registering a workspace.
Environment Variables:
- Variables are merged by name
- Later configurations override earlier ones
- Example: If workspace sets
DEBUG=falseand agent setsDEBUG=true, the final value isDEBUG=true
Mount Paths:
- Mounts are deduplicated by
host+targetpair (duplicates removed) - Order is preserved (first occurrence wins)
- Example: If workspace has mounts for
.gitconfigand.ssh, and global adds.sshand.kube, the result contains.gitconfig,.ssh, and.kube
All multi-level configurations are optional:
- If
agents.jsondoesn't exist, agent-specific configuration is skipped - If
projects.jsondoesn't exist, project and global configurations are skipped - If
workspace.jsondoesn't exist, only user-specific configurations are used
The system works without any configuration files and merges only the ones that exist.
Workspace config (.kortex/workspace.json - committed to git):
{
"environment": [
{"name": "NODE_ENV", "value": "development"}
]
}Global config (~/.kortex-cli/config/projects.json - your machine only):
{
"": {
"mounts": [
{"host": "$HOME/.gitconfig", "target": "$HOME/.gitconfig"},
{"host": "$HOME/.ssh", "target": "$HOME/.ssh"}
]
}
}Project config (~/.kortex-cli/config/projects.json - your machine only):
{
"github.com/kortex-hub/kortex-cli": {
"environment": [
{"name": "DEBUG", "value": "true"}
]
}
}Agent config (~/.kortex-cli/config/agents.json - your machine only):
{
"claude": {
"environment": [
{"name": "CLAUDE_VERBOSE", "value": "true"}
]
}
}Result when running kortex-cli init --runtime podman --agent claude:
- Environment:
NODE_ENV=development,DEBUG=true,CLAUDE_VERBOSE=true - Mounts:
$HOME/.gitconfig,$HOME/.ssh
Registers a new workspace with kortex-cli, making it available for agent launch and configuration.
kortex-cli init [sources-directory] [flags]sources-directory- Path to the directory containing your project source files (optional, defaults to current directory.)
--runtime, -r <type>- Runtime to use for the workspace (required ifKORTEX_CLI_DEFAULT_RUNTIMEis not set)--agent, -a <name>- Agent to use for the workspace (required ifKORTEX_CLI_DEFAULT_AGENTis not set)--workspace-configuration <path>- Directory for workspace configuration files (default:<sources-directory>/.kortex)--name, -n <name>- Human-readable name for the workspace (default: generated from sources directory)--project, -p <identifier>- Custom project identifier to override auto-detection (default: auto-detected from git repository or source directory)--start- Start the workspace after registration (can also be set viaKORTEX_CLI_INIT_AUTO_STARTenvironment variable)--verbose, -v- Show detailed output including all workspace information--output, -o <format>- Output format (supported:json)--show-logs- Show stdout and stderr from runtime commands (cannot be combined with--output json)--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
Register the current directory:
kortex-cli init --runtime podman --agent claudeOutput: a1b2c3d4e5f6... (workspace ID)
Register a specific directory:
kortex-cli init /path/to/myproject --runtime podman --agent claudeRegister with a custom name:
kortex-cli init /path/to/myproject --runtime podman --agent claude --name "my-awesome-project"Register with a custom project identifier:
kortex-cli init /path/to/myproject --runtime podman --agent claude --project "my project"Register with custom configuration location:
kortex-cli init /path/to/myproject --runtime podman --agent claude --workspace-configuration /path/to/configRegister and start immediately:
kortex-cli init /path/to/myproject --runtime podman --agent claude --startOutput: a1b2c3d4e5f6... (workspace ID, workspace is now running)
Register and start using environment variable:
export KORTEX_CLI_INIT_AUTO_START=1
kortex-cli init /path/to/myproject --runtime podman --agent claudeOutput: a1b2c3d4e5f6... (workspace ID, workspace is now running)
View detailed output:
kortex-cli init --runtime podman --agent claude --verboseOutput:
Registered workspace:
ID: a1b2c3d4e5f6...
Name: myproject
Project: /absolute/path/to/myproject
Agent: claude
Sources directory: /absolute/path/to/myproject
Configuration directory: /absolute/path/to/myproject/.kortex
State: stopped
JSON output (default - ID only):
kortex-cli init /path/to/myproject --runtime podman --agent claude --output jsonOutput:
{
"id": "a1b2c3d4e5f6..."
}JSON output with verbose flag (full workspace details):
kortex-cli init /path/to/myproject --runtime podman --agent claude --output json --verboseOutput:
{
"id": "a1b2c3d4e5f6...",
"name": "myproject",
"agent": "claude",
"project": "/absolute/path/to/myproject",
"state": "stopped",
"paths": {
"source": "/absolute/path/to/myproject",
"configuration": "/absolute/path/to/myproject/.kortex"
}
}JSON output with short flags:
kortex-cli init -r fake -a claude -o json -vShow runtime command output (e.g., image build logs):
kortex-cli init --runtime podman --agent claude --show-logs- If
--nameis not provided, the name is automatically generated from the last component of the sources directory path - If a workspace with the same name already exists, kortex-cli automatically appends an increment (
-2,-3, etc.) to ensure uniqueness
Examples:
# First workspace in /home/user/project
kortex-cli init /home/user/project --runtime podman --agent claude
# Name: "project"
# Second workspace with the same directory name
kortex-cli init /home/user/another-location/project --runtime podman --agent claude --name "project"
# Name: "project-2"
# Third workspace with the same name
kortex-cli init /tmp/project --runtime podman --agent claude --name "project"
# Name: "project-3"When registering a workspace, kortex-cli automatically detects and stores a project identifier. This allows grouping workspaces that belong to the same project, even across different branches, forks, or subdirectories.
The project is determined using the following rules:
1. Git repository with remote URL
The project is the repository remote URL (without .git suffix) plus the workspace's relative path within the repository:
- At repository root:
https://github.com/user/repo/ - In subdirectory:
https://github.com/user/repo/sub/path
Remote priority:
upstreamremote is checked first (useful for forks)originremote is used ifupstreamdoesn't exist- If neither exists, falls back to local repository path (see below)
Example - Fork with upstream:
# Repository setup:
# upstream: https://github.com/kortex-hub/kortex-cli.git
# origin: https://github.com/myuser/kortex-cli.git (fork)
# Workspace at repository root
kortex-cli init /home/user/kortex-cli --runtime podman --agent claude
# Project: https://github.com/kortex-hub/kortex-cli/
# Workspace in subdirectory
kortex-cli init /home/user/kortex-cli/pkg/git --runtime podman --agent claude
# Project: https://github.com/kortex-hub/kortex-cli/pkg/gitThis ensures all forks and branches of the same upstream repository are grouped together.
2. Git repository without remote
The project is the repository root directory path plus the workspace's relative path:
- At repository root:
/home/user/my-local-repo - In subdirectory:
/home/user/my-local-repo/sub/path
Example - Local repository:
# Workspace at repository root
kortex-cli init /home/user/local-repo --runtime podman --agent claude
# Project: /home/user/local-repo
# Workspace in subdirectory
kortex-cli init /home/user/local-repo/pkg/utils --runtime podman --agent claude
# Project: /home/user/local-repo/pkg/utils3. Non-git directory
The project is the workspace source directory path:
Example - Regular directory:
kortex-cli init /tmp/workspace --runtime podman --agent claude
# Project: /tmp/workspaceBenefits:
- Cross-branch grouping: Workspaces in different git worktrees or branches of the same repository share the same project
- Fork grouping: Forks reference the upstream repository, grouping all contributors working on the same project
- Subdirectory support: Monorepo subdirectories are tracked with their full path for precise identification
- Custom override: Use
--projectflag to manually group workspaces under a custom identifier (e.g., "client-project") - Future filtering: The project field enables filtering and grouping commands (e.g., list all workspaces for a specific project)
- Runtime is required: You must specify a runtime using either the
--runtimeflag or theKORTEX_CLI_DEFAULT_RUNTIMEenvironment variable - Agent is required: You must specify an agent using either the
--agentflag or theKORTEX_CLI_DEFAULT_AGENTenvironment variable - Project auto-detection: The project identifier is automatically detected from git repository information or source directory path. Use
--projectflag to override with a custom identifier - Auto-start: Use the
--startflag or setKORTEX_CLI_INIT_AUTO_START=1to automatically start the workspace after registration, combininginitandstartinto a single operation - All directory paths are converted to absolute paths for consistency
- The workspace ID is a unique identifier generated automatically
- Workspaces can be listed using the
workspace listcommand - The default configuration directory (
.kortex) is created inside the sources directory unless specified otherwise - JSON output format is useful for scripting and automation
- Without
--verbose, JSON output returns only the workspace ID - With
--verbose, JSON output includes full workspace details (ID, name, agent, paths) - Use
--show-logsto display the full stdout and stderr from runtime commands (e.g.,podman buildoutput during image creation) - JSON error handling: When
--output jsonis used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure
Lists all workspaces that have been registered with kortex-cli. Also available as the shorter alias list.
kortex-cli workspace list [flags]
kortex-cli list [flags]--output, -o <format>- Output format (supported:json)--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
List all workspaces (human-readable format):
kortex-cli workspace listOutput:
ID: a1b2c3d4e5f6...
Name: myproject
Project: /absolute/path/to/myproject
Agent: claude
Sources: /absolute/path/to/myproject
Configuration: /absolute/path/to/myproject/.kortex
State: running
ID: f6e5d4c3b2a1...
Name: another-project
Project: /absolute/path/to/another-project
Agent: goose
Sources: /absolute/path/to/another-project
Configuration: /absolute/path/to/another-project/.kortex
State: stopped
Use the short alias:
kortex-cli listList workspaces in JSON format:
kortex-cli workspace list --output jsonOutput:
{
"items": [
{
"id": "a1b2c3d4e5f6...",
"name": "myproject",
"agent": "claude",
"project": "/absolute/path/to/myproject",
"state": "running",
"paths": {
"source": "/absolute/path/to/myproject",
"configuration": "/absolute/path/to/myproject/.kortex"
}
},
{
"id": "f6e5d4c3b2a1...",
"name": "another-project",
"agent": "goose",
"project": "/absolute/path/to/another-project",
"state": "stopped",
"paths": {
"source": "/absolute/path/to/another-project",
"configuration": "/absolute/path/to/another-project/.kortex"
}
}
]
}List with short flag:
kortex-cli list -o json- When no workspaces are registered, the command displays "No workspaces registered"
- The JSON output format is useful for scripting and automation
- All paths are displayed as absolute paths for consistency
- JSON error handling: When
--output jsonis used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure
Starts a registered workspace by its name or ID. Also available as the shorter alias start.
kortex-cli workspace start NAME|ID [flags]
kortex-cli start NAME|ID [flags]NAME|ID- The workspace name or unique identifier (required)
--output, -o <format>- Output format (supported:json)--show-logs- Show stdout and stderr from runtime commands (cannot be combined with--output json)--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
Start a workspace by ID:
kortex-cli workspace start a1b2c3d4e5f6...Output: a1b2c3d4e5f6... (ID of started workspace)
Start a workspace by name:
kortex-cli workspace start my-projectOutput: a1b2c3d4e5f6... (ID of started workspace)
Use the short alias:
kortex-cli start my-projectView workspace names and IDs before starting:
# First, list all workspaces to find the name or ID
kortex-cli list
# Then start the desired workspace (using either name or ID)
kortex-cli start my-projectJSON output:
kortex-cli workspace start a1b2c3d4e5f6... --output jsonOutput:
{
"id": "a1b2c3d4e5f6..."
}JSON output with short flag:
kortex-cli start a1b2c3d4e5f6... -o jsonShow runtime command output:
kortex-cli workspace start a1b2c3d4e5f6... --show-logsWorkspace not found (text format):
kortex-cli start invalid-idOutput:
Error: workspace not found: invalid-id
Use 'workspace list' to see available workspaces
Workspace not found (JSON format):
kortex-cli start invalid-id --output jsonOutput:
{
"error": "workspace not found: invalid-id"
}- You can specify the workspace using either its name or ID (both can be obtained using the
workspace listorlistcommand) - The command always outputs the workspace ID, even when started by name
- Starting a workspace launches its associated runtime instance
- The workspace runtime state is updated to reflect that it's running
- JSON output format is useful for scripting and automation
- When using
--output json, errors are also returned in JSON format for consistent parsing - JSON error handling: When
--output jsonis used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure
Stops a running workspace by its name or ID. Also available as the shorter alias stop.
kortex-cli workspace stop NAME|ID [flags]
kortex-cli stop NAME|ID [flags]NAME|ID- The workspace name or unique identifier (required)
--output, -o <format>- Output format (supported:json)--show-logs- Show stdout and stderr from runtime commands (cannot be combined with--output json)--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
Stop a workspace by ID:
kortex-cli workspace stop a1b2c3d4e5f6...Output: a1b2c3d4e5f6... (ID of stopped workspace)
Stop a workspace by name:
kortex-cli workspace stop my-projectOutput: a1b2c3d4e5f6... (ID of stopped workspace)
Use the short alias:
kortex-cli stop my-projectView workspace names and IDs before stopping:
# First, list all workspaces to find the name or ID
kortex-cli list
# Then stop the desired workspace (using either name or ID)
kortex-cli stop my-projectJSON output:
kortex-cli workspace stop a1b2c3d4e5f6... --output jsonOutput:
{
"id": "a1b2c3d4e5f6..."
}JSON output with short flag:
kortex-cli stop a1b2c3d4e5f6... -o jsonShow runtime command output:
kortex-cli workspace stop a1b2c3d4e5f6... --show-logsWorkspace not found (text format):
kortex-cli stop invalid-idOutput:
Error: workspace not found: invalid-id
Use 'workspace list' to see available workspaces
Workspace not found (JSON format):
kortex-cli stop invalid-id --output jsonOutput:
{
"error": "workspace not found: invalid-id"
}- You can specify the workspace using either its name or ID (both can be obtained using the
workspace listorlistcommand) - The command always outputs the workspace ID, even when stopped by name
- Stopping a workspace stops its associated runtime instance
- The workspace runtime state is updated to reflect that it's stopped
- JSON output format is useful for scripting and automation
- When using
--output json, errors are also returned in JSON format for consistent parsing - JSON error handling: When
--output jsonis used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure
Connects to a running workspace with an interactive terminal session. Also available as the shorter alias terminal.
kortex-cli workspace terminal NAME|ID [COMMAND...] [flags]
kortex-cli terminal NAME|ID [COMMAND...] [flags]NAME|ID- The workspace name or unique identifier (required)COMMAND...- Optional command to execute instead of the default agent command
--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
Connect using the default agent command (by ID):
kortex-cli workspace terminal a1b2c3d4e5f6...Connect using the default agent command (by name):
kortex-cli workspace terminal my-projectThis starts an interactive session with the default agent (typically Claude Code) inside the running workspace container.
Use the short alias:
kortex-cli terminal my-projectRun a bash shell:
kortex-cli terminal my-project bashRun a command with flags (use -- to prevent kortex-cli from parsing them):
kortex-cli terminal a1b2c3d4e5f6... -- bash -c 'echo hello'The -- separator tells kortex-cli to stop parsing flags and pass everything after it directly to the container. This is useful when your command includes flags that would otherwise be interpreted by kortex-cli.
List workspaces and connect to a running one:
# First, list all workspaces to find the ID
kortex-cli list
# Start a workspace if it's not running
kortex-cli start a1b2c3d4e5f6...
# Then connect with a terminal
kortex-cli terminal a1b2c3d4e5f6...Workspace not found:
kortex-cli terminal invalid-idOutput:
Error: workspace not found: invalid-id
Use 'workspace list' to see available workspaces
Workspace not running:
kortex-cli terminal a1b2c3d4e5f6...Output:
Error: instance is not running (current state: created)
In this case, you need to start the workspace first:
kortex-cli start a1b2c3d4e5f6...
kortex-cli terminal a1b2c3d4e5f6...- The workspace must be in a running state before you can connect to it. Use
workspace startto start a workspace first - You can specify the workspace using either its name or ID (both can be obtained using the
workspace listorlistcommand) - By default (when no command is provided), the runtime uses the
terminal_commandfrom the agent's configuration file- For example, if the workspace was created with
--agent claude, it will use the command defined inclaude.json(typically["claude"]) - This ensures you connect directly to the configured agent
- For example, if the workspace was created with
- You can override the default by providing a custom command (e.g.,
bash,python, or any executable available in the container) - Use the
--separator when your command includes flags to prevent kortex-cli from trying to parse them - The terminal session is fully interactive with stdin/stdout/stderr connected to your terminal
- The command execution happens inside the workspace's container/runtime environment
- JSON output is not supported for this command as it's inherently interactive
- Runtime support: The terminal command requires the runtime to implement the Terminal interface. The Podman runtime supports this using
podman exec -it
Removes a registered workspace by its name or ID. Also available as the shorter alias remove.
kortex-cli workspace remove NAME|ID [flags]
kortex-cli remove NAME|ID [flags]NAME|ID- The workspace name or unique identifier (required)
--force, -f- Stop the workspace if it is running before removing it--output, -o <format>- Output format (supported:json)--show-logs- Show stdout and stderr from runtime commands (cannot be combined with--output json)--storage <path>- Storage directory for kortex-cli data (default:$HOME/.kortex-cli)
Remove a workspace by ID:
kortex-cli workspace remove a1b2c3d4e5f6...Output: a1b2c3d4e5f6... (ID of removed workspace)
Remove a workspace by name:
kortex-cli workspace remove my-projectOutput: a1b2c3d4e5f6... (ID of removed workspace)
Use the short alias:
kortex-cli remove my-projectView workspace names and IDs before removing:
# First, list all workspaces to find the name or ID
kortex-cli list
# Then remove the desired workspace (using either name or ID)
kortex-cli remove my-projectRemove a running workspace (stops it first):
kortex-cli workspace remove a1b2c3d4e5f6... --forceOutput: a1b2c3d4e5f6... (ID of removed workspace)
JSON output:
kortex-cli workspace remove a1b2c3d4e5f6... --output jsonOutput:
{
"id": "a1b2c3d4e5f6..."
}JSON output with short flag:
kortex-cli remove a1b2c3d4e5f6... -o jsonShow runtime command output:
kortex-cli workspace remove a1b2c3d4e5f6... --show-logsWorkspace not found (text format):
kortex-cli remove invalid-idOutput:
Error: workspace not found: invalid-id
Use 'workspace list' to see available workspaces
Workspace not found (JSON format):
kortex-cli remove invalid-id --output jsonOutput:
{
"error": "workspace not found: invalid-id"
}Removing a running workspace without --force:
Attempting to remove a running workspace without --force will fail because the runtime refuses to remove a running instance. Stop the workspace first, or use --force:
# Stop first, then remove
kortex-cli stop a1b2c3d4e5f6...
kortex-cli remove a1b2c3d4e5f6...
# Or remove in one step
kortex-cli remove a1b2c3d4e5f6... --force- You can specify the workspace using either its name or ID (both can be obtained using the
workspace listorlistcommand) - The command always outputs the workspace ID, even when removed by name
- Removing a workspace only unregisters it from kortex-cli; it does not delete any files from the sources or configuration directories
- If the workspace name or ID is not found, the command will fail with a helpful error message
- Use
--forceto automatically stop a running workspace before removing it; without this flag, removing a running workspace will fail - Tab completion for this command suggests only non-running workspaces by default; when
--forceis specified, all workspaces are suggested - JSON output format is useful for scripting and automation
- When using
--output json, errors are also returned in JSON format for consistent parsing - JSON error handling: When
--output jsonis used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure