# Design / ADR: Tool Container Home Directory

## Status

Proposed

## Context

Tool containers currently mix home-directory conventions:

- Legacy `dockerfile` and `compose` tool types mount the repository at `/workspace` and run as `root`.
- Manifest-based tool types may run as a non-root user (`user`) and already support `~` / `$HOME` expansion to `/home/{user.name}` via the `home-path-expansion` work.
- `tool-images/base.dockerfile` already creates a `user` with `WORKDIR /home/user`, but the platform does not guarantee this for all tool types.

Users expect a predictable, writable home directory inside every tool container and want the repository/workspace to live under it, preserving the repository's root directory name so paths are meaningful (e.g., `/home/user/my-app`, not `/home/user/workspace` or a generic `/workspace`).

## Goals

1. Provide a **configurable workspace/home directory** that **defaults to `/home/user`** for all tool containers.
2. Mount the repository/workspace under that directory using the **actual directory name** (`{repo_name}` or `{workspace_name}`).
3. Make the setting part of the **ToolType / manifest definition** so tool authors control it.
4. Keep **`manifest.user.name`** as the runtime user; the new field controls the directory path.
5. Preserve **`/workspace` as a compatibility symlink** to avoid breaking existing scripts, bookmarks, and settings.
6. Ensure **config-profile and git mounts** staged by the API remain writable by the non-root container user.

## Non-Goals

- Changing the container runtime user model (still driven by `manifest.user`).
- Moving non-tool services (API, web, Postgres, Redis) under `/home/user`.
- Forcing every existing manifest to migrate; explicit repo mount targets remain respected.
- Adding a frontend UI for the new field in this iteration (backend field + manifest schema change only).

## Decision

### Configuration surface

Add a `home_directory` field to the ToolType model and the manifest schema. It defaults to `/home/user` and can be overridden per tool type.

- **ToolType level**: `ToolType.home_directory: str = "/home/user"` (non-nullable, default).
- **Manifest level**: `manifest.home_directory: str` (optional; if absent, fall back to `ToolType.home_directory`).

The runtime home directory for a container is resolved in this precedence order:

1. Manifest `home_directory` if present.
2. ToolType `home_directory` (database column, default `/home/user`).
3. Legacy fallback: `/root` for compose/dockerfile tools without the new field.

### What `home_directory` controls

1. **Repository/workspace mount target** when no explicit repo mount is defined:
   - Repositories: `{home_directory}/{repo_name}`
   - Workspaces: `{home_directory}/{workspace_name}` (fall back to `{repo_name}`)
2. **Dockerfile `HOME` environment variable** for manifest tools: `ENV HOME={home_directory}`.
3. **Dockerfile `WORKDIR`** for manifest tools (when no explicit `runtime.working_dir` overrides it).
4. **Base for `~` / `$HOME` expansion** in config-profile mounts and git-mount mappings.

### Precedence: explicit manifest mount wins

If a manifest already contains a mount with `source_type: repo` and an explicit `target`, that target is used unchanged. `home_directory` is only used to synthesize the default repo/workspace mount when none is explicitly specified.

### Migration for legacy tools

Use an **Alembic data migration**:

1. Add `home_directory` column to `tool_types`.
2. Set existing rows to `/home/user`.
3. Rewrite stored `compose_template` and `dockerfile_template` strings to replace `/workspace` with `{home_directory}/{{WORKSPACE_NAME}}` (or equivalent template variable) where the mount target is the workspace.

The migration is reversible via downgrade: restore the original `/workspace` strings and drop the column.

### `/workspace` compatibility

Keep `/workspace` as a symlink inside the container pointing to the resolved repo/workspace target (e.g., `/home/user/my-app`). This protects:

- Existing user startup commands and scripts.
- Bookmarks and IDE settings that reference `/workspace`.
- Legacy templates that were migrated.

The symlink is created by the generated Dockerfile (or startup entrypoint) because the actual repo is mounted at runtime.

### Permission model

Use an **entrypoint permission fixer** at container startup:

- Run as `root` (or via `sudo`) before switching to the runtime user.
- Chown mounted paths under `{home_directory}` to the container user.
- Avoid `chown -R` on large repo subtrees; chown the top-level directories and rely on the runtime user owning newly created files.
- This handles config-profile and git mounts that arrive at runtime as bind mounts from the host, which may otherwise be owned by `root` because the API stages them.

## Consequences

### Positive

- Predictable, user-writable home directory across all tool containers.
- Repository mount paths are meaningful (`/home/user/my-app`).
- Backward-compatible symlink keeps existing user data and scripts working.
- Tool authors can opt into other home directories without changing the runtime user.

### Negative / Risks

- Requires an Alembic data migration that rewrites stored templates; downgrade must be carefully tested.
- Entrypoint permission fixer adds startup complexity and requires `root`/`sudo` inside the container.
- Creating `/workspace` symlink at build time vs. runtime needs care because the target may not exist until the repo is mounted.
- Legacy `tool-images/base.dockerfile` runs as `USER user`; it will need an entrypoint that can elevate permissions or the base image must be adjusted.

## Related Documents

- `openspec/designs/home-path-expansion.md`
- `openspec/specs/home-path-expansion.md`
- `openspec/tasks/home-path-expansion.md`
- `docs/superpowers/plans/tool-container-home-directory.md`
- `docs/superpowers/specs/tool-container-home-directory-test-plan.md`
