feat: remove config/state mounts from built-in tool configs

- Remove pi_state and pi_config mounts from the pi-agent manifest.
- Add Alembic data migration to strip those mounts from existing DB rows.
- Remove opencode_home:/tmp volume and HOME=/tmp override from the opencode
  built-in compose template; config/state now belongs in config profiles.
- Workspace and SSH key mounts remain unchanged.

Quality gates: python3 -m py_compile, pytest (311 passed, 34 skipped),
npm run typecheck, npm run lint
This commit is contained in:
Developer
2026-06-13 11:35:55 +00:00
parent 315cb33e3f
commit 8bde9a213c
6 changed files with 158 additions and 21 deletions
@@ -232,20 +232,6 @@ def upgrade() -> None:
"writable": True,
"owner": "user",
},
{
"name": "pi_state",
"target": "/tmp/.pi/agents",
"source_type": "instance",
"writable": True,
},
{
"name": "pi_config",
"target": "/home/user/.pi",
"source_type": "git_mount",
"git_mount_ref": "dotfiles",
"writable": True,
"owner": "user",
},
],
"runtime": {
"command": ["/bin/bash"],
@@ -0,0 +1,112 @@
"""remove pi config and state mounts from pi-agent manifest
Revision ID: 8c6d1dbd4798
Revises: 2026_06_13_make_clone_mode_nullable
Create Date: 2026-06-13 11:21:25.983178
"""
import json
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '8c6d1dbd4798'
down_revision = '2026_06_13_make_clone_mode_nullable'
branch_labels = None
depends_on = None
def _load_manifest(manifest_json):
return manifest_json if isinstance(manifest_json, dict) else json.loads(manifest_json)
def upgrade() -> None:
"""Remove pi_state and pi_config mounts from the pi-agent manifest."""
conn = op.get_bind()
result = conn.execute(
sa.text(
"SELECT id, manifest FROM tool_definition_manifests WHERE name = 'pi-agent'"
)
)
row = result.fetchone()
if not row:
return
manifest_id, manifest_json = row
manifest = _load_manifest(manifest_json)
mounts = manifest.get("mounts", [])
original_count = len(mounts)
filtered_mounts = [
m for m in mounts if m.get("name") not in ("pi_state", "pi_config")
]
if len(filtered_mounts) < original_count:
manifest["mounts"] = filtered_mounts
conn.execute(
sa.text(
"UPDATE tool_definition_manifests SET manifest = :manifest WHERE id = :id"
),
{
"manifest": json.dumps(manifest),
"id": manifest_id,
},
)
def downgrade() -> None:
"""Restore pi_state and pi_config mounts to the pi-agent manifest."""
conn = op.get_bind()
result = conn.execute(
sa.text(
"SELECT id, manifest FROM tool_definition_manifests WHERE name = 'pi-agent'"
)
)
row = result.fetchone()
if not row:
return
manifest_id, manifest_json = row
manifest = _load_manifest(manifest_json)
mounts = manifest.get("mounts", [])
existing_names = {m.get("name") for m in mounts}
if "pi_state" not in existing_names:
mounts.append(
{
"name": "pi_state",
"target": "/tmp/.pi/agents",
"source_type": "instance",
"writable": True,
}
)
if "pi_config" not in existing_names:
mounts.append(
{
"name": "pi_config",
"target": "/home/user/.pi",
"source_type": "git_mount",
"git_mount_ref": "dotfiles",
"writable": True,
"owner": "user",
}
)
manifest["mounts"] = mounts
conn.execute(
sa.text(
"UPDATE tool_definition_manifests SET manifest = :manifest WHERE id = :id"
),
{
"manifest": json.dumps(manifest),
"id": manifest_id,
},
)
+1 -7
View File
@@ -103,11 +103,8 @@ services:
image: node:20-slim
container_name: {{TOOL_NAME}}
working_dir: /workspace
environment:
- HOME=/tmp
volumes:
- {{REPO_PATH}}:/workspace
- opencode_home:/tmp
ports:
- "3000:3000"
command: >
@@ -125,10 +122,7 @@ services:
exec tail -f /dev/null"
stdin_open: true
tty: true
restart: unless-stopped
volumes:
opencode_home:""",
restart: unless-stopped""",
"required_variables": ["REPO_PATH", "TOOL_NAME"],
},
]
@@ -0,0 +1,4 @@
name: tool-config-mount-cleanup
status: completed
completed_at: 2026-06-13
started_at: 2026-06-12
@@ -0,0 +1,33 @@
# Tool config mount cleanup
## Problem
The built-in tool definitions currently declare configuration and state mounts that belong in user-controlled config profiles:
- The `pi-agent` manifest mounts `pi_state` (`/tmp/.pi/agents`) and `pi_config` (`/home/user/.pi`) via a `git_mount` reference.
- The `opencode` built-in compose template mounts a named volume `opencode_home:/tmp` and sets `HOME=/tmp`.
These require manual configuration or implicit state persistence, which conflicts with the design that tool configs should only set up the actual tool, while config profiles handle user-specific configuration and state.
## Decision
Remove all configuration/state mounts from built-in tool definitions. Tool configs will declare only:
- Runtime environment (packages, user, command, ports).
- The workspace/repository mount.
- SSH key mounts supplied by the platform.
User-specific configuration and state will be handled exclusively by config profiles.
## Scope
- Remove `pi_state` and `pi_config` mounts from the `pi-agent` manifest.
- Update the original migration that inserts the `pi-agent` manifest.
- Add a data migration to remove those mounts from existing `tool_definition_manifests` rows.
- Remove the `opencode_home:/tmp` volume and `HOME=/tmp` override from the `opencode` built-in compose template.
## Non-goals
- No changes to config profile behavior.
- No changes to workspace or SSH key mounts.
- No changes to tool image Dockerfiles beyond what is required by mount removal.
@@ -0,0 +1,8 @@
# Tasks
- [x] Identify all built-in tool configs with configuration or state mounts.
- [x] Remove `pi_state` and `pi_config` mounts from the `pi-agent` manifest in `apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py`.
- [x] Create an Alembic data migration to remove those mounts from existing `tool_definition_manifests` rows.
- [x] Remove the `opencode_home:/tmp` volume and `HOME=/tmp` environment variable from the `opencode` compose template in `apps/api/src/seeds/builtin_tool_types.py`.
- [x] Run backend quality gates (`py_compile`, `pytest`).
- [x] Commit, merge to `dev`, push.