Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 139 additions & 9 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Default configuration for most development work. Includes:
- Azure CLI, GitHub CLI
- Claude Code

**Note:** The Electron shell requires GUI support. To use the shell with devcontainer, you need to start teh agent-server in the container and run the shell on your host machine. The agent server port is forwarded to the host, so the shell will connect correctly:
**Note:** The Electron shell requires GUI support. To use the shell with devcontainer, you need to start the agent-server in the container and run the shell on your host machine. The agent server port is forwarded to the host, so the shell will connect correctly:

```bash
# In container - start the backend
Expand All @@ -54,6 +54,78 @@ cd ts && pnpm run shell

## Working with the Container

### SSH Access

The universal devcontainer image includes an SSH server. To set up key-based
access from your host machine, run:

```bash
.devcontainer/scripts/setup-ssh-access.sh
```

The script will:

- create `~/.ssh/typeagent-devcontainer` if it does not already exist
- find the running TypeAgent devcontainer from Docker labels
- add the public key to `~/.ssh/authorized_keys` for the `codespace` user in the container
- add or update an SSH config entry named `typeagent-devcontainer`
- enforce key-only SSH auth in both client config and container sshd settings
- use `StrictHostKeyChecking accept-new` by default
- when run in WSL, also detect your Windows `%USERPROFILE%/.ssh` directory
- copy the same keypair into Windows `~/.ssh` so Windows OpenSSH can use it directly
- add or update the same `typeagent-devcontainer` host entry in Windows SSH config
- use Windows-native paths for the copied key and `known_hosts` entry in that Windows config

By default, generated SSH config uses `StrictHostKeyChecking accept-new`.
For local-only workflows where you intentionally want host key checks disabled,
use:

```bash
.devcontainer/scripts/setup-ssh-access.sh --insecure-local
```

After it completes, connect with:

```bash
ssh typeagent-devcontainer
```

If you use a non-default devcontainer config, pass it explicitly:

```bash
.devcontainer/scripts/setup-ssh-access.sh --config .devcontainer/vnc/devcontainer.json
```

### One-Command Start (and Optional SSH Setup)

Use this wrapper to start the devcontainer from the command line. If your
VS Code agent window only supports tunnel/SSH connections, pass `--ssh` to
also configure host SSH access in the same step:

```bash
.devcontainer/scripts/start-devcontainer.sh # start only
.devcontainer/scripts/start-devcontainer.sh --ssh # start + configure SSH
```

Useful options:

```bash
# Recreate container first
.devcontainer/scripts/start-devcontainer.sh --remove-existing-container --ssh

# Use alternate devcontainer config
.devcontainer/scripts/start-devcontainer.sh --config .devcontainer/vnc/devcontainer.json

# Local-only mode with host key checks disabled (implies --ssh)
.devcontainer/scripts/start-devcontainer.sh --insecure-local
```

After it completes with `--ssh`:

```bash
ssh typeagent-devcontainer
```

### Common Commands

```bash
Expand All @@ -64,6 +136,24 @@ pnpm run test:local # Run unit tests
pnpm run start:agent-server # Start agent server
```

### Git Configuration

During container creation, the post-create script keeps any existing container
Git identity, or sets `user.name` and `user.email` from the
`LOCAL_GIT_USER_NAME` and `LOCAL_GIT_USER_EMAIL` environment variables when
those values are provided. The devcontainer configs pass those host-side
environment variables through with `${localEnv:...}`, and the
`start-devcontainer.sh` wrapper fills them from your host `~/.gitconfig`
using `git config --global` before calling `devcontainer up`.

After rebuilding the container, you can verify with:

```bash
git config --global --list
git config user.name
git config user.email
```

## Using with AI Agents

### Claude Code
Expand Down Expand Up @@ -99,14 +189,32 @@ Each worktree shares the git history but has independent:

## Forwarded Ports

| Port | Service |
| ---- | ------------------------------- |
| 3000 | API Server (HTTP) |
| 3443 | API Server (HTTPS) |
| 8999 | Agent Server (WebSocket) |
| 8081 | Browser Agent (WebSocket) |
| 8082 | Code Agent (WebSocket) |
| 6080 | noVNC Desktop (VNC config only) |
Standard config (`devcontainer.json`):

| Port | Service |
| ---- | ----------------------------------------------- |
| 2222 | Dev Container SSH (host-published on 127.0.0.1) |
| 3000 | API Server (HTTP) |
| 3443 | API Server (HTTPS) |
| 8999 | Agent Server (WebSocket) |
| 8081 | Browser Agent (WebSocket) |
| 8082 | Code Agent (WebSocket) |

VNC config (`vnc/devcontainer.json`) adds:

| Port | Service |
| ---- | ----------------- |
| 6080 | noVNC Web Desktop |
| 5901 | VNC Client |

## Container User

The container runs as `codespace` with UID/GID 1001 (matches the Codespaces
convention and the previous universal base image). All workspace and cache
paths are accessed via Docker named volumes, not host bind mounts of source
files, so this UID does not need to match your host user. If you add a host
bind mount later and your host user shares UID 1001, be aware of the implicit
file-ownership overlap.

## Troubleshooting

Expand Down Expand Up @@ -150,6 +258,28 @@ The container runs as the `codespace` user. If you encounter permission issues:
sudo chown -R codespace:codespace /workspaces/TypeAgent
```

### Agent window cannot create `/workspaces/*.worktrees` (access denied)

Agent windows may create sibling worktree folders such as
`/workspaces/TypeAgent3.worktrees`.
If this path is root-owned, worktree creation fails with access denied.

Run:

```bash
sudo mkdir -p /workspaces/TypeAgent3.worktrees
sudo chown codespace:codespace /workspaces/TypeAgent3.worktrees
```

Then retry creating the worktree.

This is also handled automatically on fresh container creation by
`.devcontainer/scripts/post-create.sh`.

The standard and VNC devcontainer configs now mount a dedicated Docker
named volume at `/workspaces/<repo>.worktrees` so agent-window worktrees
have a stable writable location across container restarts and rebuilds.

### Line ending issues (Windows)

If scripts fail with `\r': command not found`, the repository may have CRLF line endings. Fix with:
Expand Down
15 changes: 15 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@
"resolved": "ghcr.io/devcontainers/features/azure-cli@sha256:4549175fbfd3475d1d62e82f6e5425d03954a6ae06027b2515b0ba41a8206417",
"integrity": "sha256:4549175fbfd3475d1d62e82f6e5425d03954a6ae06027b2515b0ba41a8206417"
},
"ghcr.io/devcontainers/features/common-utils:2": {
"version": "2.5.8",
"resolved": "ghcr.io/devcontainers/features/common-utils@sha256:c42fdefe6d737a3a6f61cc52b23c7c9a565d08cc4d9c303669a7cf2ee5fd81fc",
"integrity": "sha256:c42fdefe6d737a3a6f61cc52b23c7c9a565d08cc4d9c303669a7cf2ee5fd81fc"
},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "2.5.0",
"resolved": "ghcr.io/devcontainers/features/dotnet@sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093",
"integrity": "sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093"
},
"ghcr.io/devcontainers/features/git-lfs:1": {
"version": "1.2.5",
"resolved": "ghcr.io/devcontainers/features/git-lfs@sha256:71c2b371cf12ab7fcec47cf17369c6f59156100dad9abf9e4c593049d789de72",
"integrity": "sha256:71c2b371cf12ab7fcec47cf17369c6f59156100dad9abf9e4c593049d789de72"
},
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "1.1.0",
"resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671",
Expand All @@ -29,6 +39,11 @@
"version": "1.8.0",
"resolved": "ghcr.io/devcontainers/features/python@sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511",
"integrity": "sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511"
},
"ghcr.io/devcontainers/features/sshd:1": {
"version": "1.1.0",
"resolved": "ghcr.io/devcontainers/features/sshd@sha256:f5251b8e4325f68f7280973c6cd65daff414449c66f240621502d4e8e74eb7ee",
"integrity": "sha256:f5251b8e4325f68f7280973c6cd65daff414449c66f240621502d4e8e74eb7ee"
}
}
}
47 changes: 35 additions & 12 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
{
"name": "TypeAgent Development",
"image": "mcr.microsoft.com/devcontainers/universal:6",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",

// Multi-arch base image (linux/amd64 and linux/arm64) so this configuration
// works on Apple Silicon as well as x86_64 hosts.
//
// This configuration works with:
// - VS Code + Docker Desktop (local)
// - VS Code + Docker Desktop (local, including macOS arm64)
// - GitHub Codespaces (cloud)
// - JetBrains IDEs with Dev Containers support

// Fix stale yarn GPG key in base image before features install
"initializeCommand": "docker run --rm mcr.microsoft.com/devcontainers/universal:6 echo 'Pulling base image...' || true",

"features": {
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {},
"ghcr.io/devcontainers/features/sshd:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/git-lfs:1": {
"autoPull": false
},
"ghcr.io/devcontainers/features/node:1": {
"version": "22",
"nodeGypDependencies": true
Expand All @@ -24,12 +30,25 @@
"version": "8.0"
},
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
// Note: common-utils removed - universal:2 already includes zsh, oh-my-zsh, and common utilities
"ghcr.io/devcontainers/features/github-cli:1": {},
// base:ubuntu-24.04 does not pre-install zsh / oh-my-zsh, so add common-utils
// and create the non-root `codespace` user expected by the rest of this config.
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": true,
"configureZshAsDefaultShell": true,
"installOhMyZsh": true,
"username": "codespace",
"userUid": "1001",
"userGid": "1001"
}
},

// Fix yarn GPG key issue in base image
"onCreateCommand": "sudo rm -f /etc/apt/sources.list.d/yarn.list || true",
// Publish SSH port on loopback only so host-side `ssh typeagent-devcontainer`
// works without exposing 2222 on the LAN. Plain `forwardPorts` is only
// honored by the VS Code / Codespaces port-forwarding UI and does NOT
// actually publish the port when the container is started via the
// devcontainer CLI, which leaves `localhost:2222` unreachable.
"appPort": ["127.0.0.1:2222:2222"],

"forwardPorts": [8999, 8081, 8082, 3000, 3443],
"portsAttributes": {
Expand All @@ -45,20 +64,24 @@
"source=pnpm-global-store,target=/home/codespace/.local/share/pnpm/store,type=volume",
// Per-container node_modules (symlinks to global store)
"source=typeagent-node_modules-${devcontainerId},target=${containerWorkspaceFolder}/ts/node_modules,type=volume",
// Per-container writable sibling worktree root for agent windows
"source=typeagent-agent-worktrees-${devcontainerId},target=/workspaces/${localWorkspaceFolderBasename}.worktrees,type=volume",
// Claude Code config persistence
"source=claude-code-config-${devcontainerId},target=/home/codespace/.claude,type=volume"
],

"containerEnv": {
"PNPM_HOME": "/home/codespace/.local/share/pnpm"
"PNPM_HOME": "/home/codespace/.local/share/pnpm",
"LOCAL_GIT_USER_NAME": "${localEnv:LOCAL_GIT_USER_NAME}",
"LOCAL_GIT_USER_EMAIL": "${localEnv:LOCAL_GIT_USER_EMAIL}"
// For Codespaces, set these as repository secrets:
// - AZURE_OPENAI_API_KEY
// - AZURE_OPENAI_ENDPOINT
// - ANTHROPIC_API_KEY (for Claude Code)
},

"postCreateCommand": "cat .devcontainer/scripts/post-create.sh | tr -d '\\r' | bash",
"postStartCommand": "cat .devcontainer/scripts/post-start.sh | tr -d '\\r' | bash",
"postCreateCommand": "bash .devcontainer/scripts/post-create.sh",
"postStartCommand": "bash .devcontainer/scripts/post-start.sh",

"customizations": {
"vscode": {
Expand Down
Loading
Loading